调试Utility进程崩溃

M55内核升级中发现Utility进程崩溃很多。以前Utility进程的崩溃只占到总崩溃量1%不到,现在却增加到了10%以上。 Utility进程崩溃的堆栈都很类似,如下: 我们看0号线程,也就是主线程。这个调用栈没有wMain函数,却有exit函数。可以看出来程序崩溃在进程退出的时候。最后的我们的代码崩溃帧是在BrokerServicesBase::~BrokerServicesBase里面,其代码如下: 我认为0号线程是正常的。我们再看1号线程。1号线程是程序发生异常,生成dump的线程。可以看到是ntdll!TppWaiterpThread引发了ntdll!KiUserExceptionDispatcher。好奇怪,异常竟然来自系统模块。我们看下Windbg的dump分析: 可以看到ExceptionCode的值为c000070a,查一下ntstatus.h头文件,值c000070a表示STATUS_THREADPOOL_HANDLE_EXCEPTION,意思是线程池等待的句柄异常,可以看到句柄是0000012c。 然后用!handle命令行查看一下进程当前拥有的句柄情况: 可以看到进程句柄表里面并没有0000012c句柄。因此我猜测可能是因为0000012c句柄已经关闭了,而TppWaiterpThread还在使用0000012c这个无效的句柄导致的异常。 因此我想收集一下句柄分配和释放的信息,然后根据dump查看一下无效的句柄是怎么分配和释放的。幸好chromium里面有一个ActiveVerifier机制,ActiveVerifier是用来跟踪句柄使用情况的,它跟踪了一部分句柄创建的和Hook了CloseHandle函数。在StartTracking和CloseHandle里面加一个我自己写的LogHandle函数,这个函数会把句柄分配和释放的StackTrace跟进句柄值记录到环境变量中。 因为Utility进程创建和释放的句柄并不多,所以把这个调试信息放在环境变量中是方便和合适的。 灰度出去,收集崩溃信息。这次果然收集到了有用的信息,先看dump分析: 这次异常的句柄值是00000198,再看看环境变量中的调试信息: 00000198果然被CloseHandle了。然后根据后面的地址查看关闭的调用栈: 从代码里面可以看到00000198句柄已经随着ChildProcess的析构而关闭变成无效了,其他地方继续使用这个句柄是有问题的。 00000198句柄是ChildProcess的shutdown_event_成员变量。这个shutdown_event_会被ChildThreadImpl传递给其IPC::SyncChannel的channel_成员。而SyncChannel的shutdown_watcher_会调用系统的RegisterWaitForSingleObject去利用线程池去等待00000198句柄对应Event。 所以问题的根源是ChildProcess的析构函数CloseHandle了shutdown_event_,但是SyncChannel里面的shutdown_watcher_通过RegisterWaitForSingleObject继续等待shutdown_event_句柄。MSDN里RegisterWaitForSingleObjec介绍说:If... Read More | Share it now!

Blink/Webkit浏览器内核崩溃分析过程总结

前两天技术团队旺旺群里有同事提出一个问题:在debug模式下,Chromium浏览器打开http://product.suning.com/125073744.html页面renderer进程就立即崩溃。团队对于Blink/Webkit内核问题的分析经验不多,故把分析过程写出一个总结,希望对大家以后分析此类问题有帮助。 多进程调试 Chromium浏览器是多进程的架构。而Blink内核在renderer进程,debug模式下,VS调试不能抓到renderer进程的异常,也就无法定位问题。所以解决问题的第一步是把VS调试器附加到问题相应的renderer进程。 Chromium已有一篇文档讲述如何调试Chromium。对于浏览器子进程的调试,有一个–wait-for-debugger-children的命令行参数。给浏览器传递这个命令行参数之后,生成的子进程都会在一开始等待调试器60秒附加上去。另外这个命令行还可以指定是plugin进程还是renderer进程。因为这次调试的对象是renderer进程,故我们在VS调试器设置–wait-for-debugger-children=renderer传递给被调试的浏览器。 重现问题 用VS打开Chromium的源代码工程,并在debug模式下运行。启动浏览器之后,新建tab页,在地址栏里输入会导致renderer进程崩溃的网址http://product.suning.com/125073744.html。这时候就是生成对应的renderer进程。这个renderer进程在60秒等待我们把调试器附加上去。 我们找到新建renderer进程的PID,然后用VS的debug->Attach... Read More | Share it now!