寻找调试棘手的Windows服务启动gremlin的想法

时间:2012-01-15 06:15:03

标签: c++ multithreading debugging windbg

在过去的几个月里,我收到了QA关于我们的一项服务的报告。在使用WinDbg检查挂起转储时,每次我发现同样的事情:Loader锁定临界区被锁定但拥有线程无处可寻。由于线程已经消失并且我能看到的唯一跟踪是它留下的全局关键部分,我没有看到在线程线程上运行了什么代码,甚至是线程来自哪个DLL,它甚至可能不是我们的(即第三方供应商)。

这个问题是非常零星的,在过去的6个月中,它看起来可能是野外自然发生的3-4次。所有其他时间,服务运行完美。所以这让我相信这是某种时机/竞争条件的事情。

最近,我决定自己去做这个。我设置了一个带有WinTask脚本的机器,该脚本不断启动/停止所述服务。好消息是,我可以在5-6小时内重现问题。

现在进行下一部分:如何隔离它?

这是我到目前为止所尝试的:

  1. 在gflags图像设置中使用“调试器”字段,以便在cdb启动时自动运行cdb下的服务。到目前为止,这已经运行了两天而且从未挂起,因此我认为调试器引入了足够的时序更改以使问题不可见。

  2. 下载了应用程序验证程序,并将进程配置为使用该程序运行。找到一个完全不相关的错误,我们创建CComBSTR临时变量,将其分配给VARIANT并将变量传递给函数调用,即使CComBSTR长时间删除了分配的字符串。不要相信这个bug是相关的,因为string是只读的,并且它运行的线程不是那个正在死的线程。

  3. 我正在发帖子,以防你们想到我不考虑的事情。

    我虽然有一个Windows实用程序人为地将负载放在CPU上并做了其他事情以使竞争条件弹出,我认为应用程序验证程序做了这样的事情,但显然它没有。有谁知道我正在采取什么,或者我只是梦想了吗?

    除非周末发生任何事情,否则我的下一步将是禁用所有调试器,返回库存并破解其中一个DllMains以记录THREAD_ATTACH / THREAD_DETACH事件。至少我能够拦截创建时死亡的线程。这可能会有所启发。

4 个答案:

答案 0 :(得分:2)

我可能尝试的是附加内核调试器,然后在Appilcation Verifier下运行该过程。 AV在它持有CS并终止仍保持CS的线程时检查是否卸载了DLL。所以这些断点应该在内核调试器中触发,然后希望你可以在行为中捕获它。希望在KD下运行它不会像用户模式调试器那样减慢速度。

答案 1 :(得分:1)

事实证明,我比解决方案更接近解决方案。随着服务在cdb下运行,这改变了时间,然后用应用程序验证程序运行它,这更改了时间(页面堆启用使分配更慢),我丢失的秘密成分是prime95.exe。以高于正常优先级的速度运行prime95.exe,确实搞砸了我试图不改变的任何时间,但它使问题显示在15分钟内。

原因:

第三方SDK,用于从硬件板获取数据。当我们的服务启动时,我们会查询不同的捕获组件的功能。查询完成后,我们释放组件实例。显然这个DLL启动了一个单独的线程,它获取了一个加载器锁,然后继续在该线程中进行一堆初始化。如果在那段时间内,我们的功能查询完成并且我们发布了组件,他们的代码将在另一个线程上调用TerminateThread(),使加载器锁永久锁定。 Prime95减慢了一切,足以让我抓住这个竞争条件并得到以下验证者停止消息:

=======================================
VERIFIER STOP 00000200: pid 0x1A8C: Thread cannot own a critical section. 

0000091C : Thread ID.
77E17340 : Critical section address.
00000000 : Critical section debug information address.
00000000 : Critical section initialization stack trace.

有趣的是,这个帖子正在“消失”,没有任何异常,所以调试器甚至不会抓住任何机会。谁使用TerminateThread ????

谢谢大家的建议和支持。我实际上开始期待在午餐期间驾驶Radioshack购买串行电缆,然后花几天时间玩KD。看起来必须等到下一次:)

答案 2 :(得分:0)

一些随机的想法:如果附加调试器没有用,那么下一步就是检测(你的最后一点)。但是如果一个线程如何在不降低整个过程的情况下死掉,你是否会在某处捕获异常?您可能也希望在那里登录。如果有帮助,您还可以将WinDbg设置为中断所有第一次机会异常。即使你没有破坏,WinDbg输出窗口也会显示第一次机会异常。

答案 3 :(得分:0)

我会尝试一个非侵入式调试器,看看怎么回事,虽然你将无法停止这个过程,你应该能够看到任何调试消息以及任何启动和停止的线程,以及它对流程性能的影响应该很小。我通常使用windbg进行调试,但我认为cbd也有类似的选项。这很可能会让你看到这个过程中发生了什么,至少开始帮助缩小范围。您可能希望确保做的一件事是重定向输出(windbg中的.logopen)以确保没有任何内容超出缓冲区。