逆Heisenbug - 单元测试仅在附加调试器时失败 [英] Inverse Heisenbug - Unit test fails only when debugger is attached

查看:243
本文介绍了逆Heisenbug - 单元测试仅在附加调试器时失败的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我最近修正了我们产品中的缺陷,其症状是访问悬挂指针导致的访问冲突。



对于良好的实践,我添加了单元测试以确保该bug不会回来。在写单元测试时,我总是回退我的缺陷修复,并确保单元测试失败,否则我知道它不能正常工作。



退出后缺陷修复,我发现我的单元测试仍然通过(不好)。当我把一个调试器附加到单元测试,看看为什么它通过,测试失败(即抛出一个异常),我可以断开,并观察到调用堆栈匹配我固定的原始缺陷的堆栈。



我没有修改Visual Studio 2005中的异常中断设置,这确实是一个关键的Win32异常,它导致测试工具终止(即没有正常的异常

异常的文本是:

 未处理在0x0040fc59在_testcase.exe中的异常:0xC0000005:
访问冲突读取位置0xcdcdcdcd。

注意:位置不总是 0xcdcdcdcd 分配但未写入的Win32堆内存)。有时它是 0x00000000 ,有时它是另一个地址。



这看起来像一个传统的Heisenbug,当通过调试器观察它时,问题消失了。在我的情况下,通过调试器观察它会出现问题!



我最初的想法是,这是一个竞争条件暴露的调试器的时间差异。但是,当我向代码添加跟踪并且与调试器分开运行时,我打印出来的数据表明应用程序应该以类似于在调试器下运行的方式中止。









b $ b

更新:我正在缩小这个问题的原因。请参阅这个问题了解更多详情。

解决方案

我已经分离了这个问题的原因 - 参见这个问题



当在调试器下运行我的测试工具时,调试环境消耗的内存意味着同一对象的后续分配/释放总是分配在不同部分的内存中。这意味着当我的测试工具试图访问一个悬挂指针,它崩溃了测试(技术上这是未定义的行为,但这是测试代码,它似乎做我需要做的)。



当从命令行运行我的测试工具时,同一对象的后续分配/释放总是重用相同内存块。这种无约束的行为意味着,当我在我的测试用例中访问实际上一个悬空指针时,发生了悬挂指针仍然指向一个有效对象。这就是为什么我没有看到崩溃。


I recently fixed a defect in our product, the symptom of which was an access violation caused by accessing a dangling pointer.

For good practice I added a unit test to ensure that the bug doesn't come back. When writing a unit test I will always back out my defect fix and ensure the unit test fails, otherwise I know it isn't doing its job properly.

After backing out the defect fix, I discovered that my unit test still passes (not good). When I attached a debugger to the unit test to see why it passes, the test failed (i.e. an exception was thrown) and I could break and observe that the call stack matched the one in the original defect which I fixed.

I didn't modify the "Break on exception" settings in Visual Studio 2005, and this is indeed a critical Win32 exception which causes the test harness to terminate (i.e. there is no graceful exception handler).

The text of the exception is:

Unhandled exception at 0x0040fc59 in _testcase.exe: 0xC0000005:
Access violation reading location 0xcdcdcdcd.

Note: The location isn't always 0xcdcdcdcd (allocated but unwritten Win32 heap memory). Sometimes it is 0x00000000, and sometimes it is another address.

This seems like the inverse of a traditional Heisenbug, where a problem goes away when observing it via a debugger. In my case, observing it via the debugger makes the problem appear!

My initial thought was that this was a race condition exposed by the timing differences in the debugger. However, when I added tracing to the code and ran it separately from the debugger, the data that I am printing out indicates to me that the application should be aborting in a similar manner to when running under the debugger. But it is not!

Any suggestions as to what could be causing this?


Update: I am narrowing in on the cause of this problem. See this question for more details. Will update this question with the answer if I find it.

解决方案

I have isolated the cause of this problem - see this question for details.

When running my test harness under the debugger, the memory consumed by the debugging environment meant that subsequent allocations/deallocations of the same object were always allocated in different parts of memory. This meant that when my test harness tried to access a dangling pointer, it crashed the test (technically this is undefined behaviour but this is test code and it seems to do what I need it to do).

When running my test harness from the command line, subsequent allocations/deallocations of the same object always re-used the same block of memory. This coincedental behaviour meant that when I accessed what was in actuality a dangling pointer in my test case, it happened that the dangling pointer still pointed to a valid object. That's why I didn't see a crash.

这篇关于逆Heisenbug - 单元测试仅在附加调试器时失败的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆