分类: WINDOWS
2009-04-02 09:56:53
Hi all:
昨日从测试同事处获悉,alii存在一定几率的无法退出情况,表现为界面已经消失,但是进程还存在,测试同事提供了dump。
分析如下:
1. 版本为6.05.09 alitalk.
2. Vc无法解析符号,均前置显示为*ntdll.dll 类似,使用windbg(饶趣同学提示),采用.reload /f /I 方能显示,始终提示timestamp不匹配,估计msvc就好似这个原因无法加载符号。
3. 据测试同事回报,是退出后发生的。
Stack 如下:(仅有两个线程,一个主线程,一个工作线程)
主线程信息….
工作线程信息
因此判断为有两个线程互锁了。
然后继续往下分析,从主线程可以看到…
1. 因为据测试同事说是退出后一端时间才发先的,因此从aliim!_tmaincrtstartup 这个frame,判断这个时候我的winmain的最后一行代码应该已经执行了,因此无法看到,是运行库进行全局反初始化时候发生的
2. 继续跟下去,发现发生问题发生在com库的反初始化,而且从dump中出现的较多的stub/rpc字样,比较容易判定为主线程在释放一个本aparmtment内的代理对象,后者说此com对象的实际运行apartment不是主线程.
3. 然后再看工作线程,工作线程貌似在等待一个criticalsec而没有返回.
我们看下工作线程的ntdll!RtlEnterCriticalSection_0x46 这个frame的第三个参数也就是0x7c99b178
这下发现了, 请注意owningthread=0xf74 , 而0xf74是谁呢? 哈哈,就是主线程,这下就找到了直接原因,就是说主线程拿住了critsec而工作线程拿不到了.
但是从主线程的stack中貌似无法直接看到也有enterciriticalsection的代码? 倒是有一个waitformultipleobject,
因此推断: 主线程进入临界区后在等待另外一个对象,而这个对象等不到。由于!htrace 无法使用因此很难继续推断!
分析到了这儿进入了一个困局,因为主线程在等待一个handle,但是从仅有的一个工作线程却并没有发现有蛛丝马迹,因此只能推断:
主线程正在等待的句柄并没有人(线程)进行触发,或者简单的说,由于aliim提出,某个线程退出了,而这个线程可能本来应该设置这个handle.
下面从两外一个角度来分析,还是围绕主线程退出时候的套件释放对象来说。
从问题的dump以及log可以分析出:
1. 并没有任何进程外的插件运行或者曾经运行过,因此排除掉主线程使用的是远程com对象
2. 从ie4_trap.dll 这个对象的stackframe可以怀疑,主线程是不是引用了一个实际创建与其它线程的ie相关对象?
3. 主线程中使用了apartment== FREE 的组件,因此拿到了一个代理对象,而实际对象位于其它线程.
4. Wwsdkcom有大量的com对象,但是每一个对象都是apartment的。
从上面的分析,继而给出解决方案
1. 在return前直接terminateprocess 杀掉自己 ,当然这样导致进程始终处于异常退出状态,如果有些反初始化工作需要进行则会受到影响,非常糟糕的解决办法
2. 在退出前启动一个线程,这个线程等待一段足够长的时间后,杀掉自己所在的进程
因此先用第二方案,看看代码大致如下:
unsigned __stdcall ExitMonitorProc(void* p)
{
Sleep(15 *1000);
::TerminateProcess(::GetCurrentProcess() , 0);
}
strKillCmdParam.Format(_T("%d") , ::GetCurrentProcessId());
_T("open"),
filesys::GetModuleDir(NULL) + _T("killapp.exe"),
strKillCmdParam,
NULL,
SW_HIDE);
结果我又用类似方法发现,结果发现依然无效,一抓堆栈:
具体图不贴了,有关细节。
shellexecute执行时候最终会调用getmodulefile这样一个API而这个api最终又死锁了,而这个锁和本来要解决的死锁还是同一个。呵呵。
当然这个问题本身并不说名,这样通过启动进程方式来杀自己还是存在问题,而是这个启动的时机有问题,
这儿说这个细节也是自己的一种经验。作为记忆。