Anatomy of a Heisenbug

I just spent a half an hour debugging a heisenbug and thought I’d pass on what was happening.

 

I was running my unit tests for one of my features and they were reliably failing.  Unfortunately the instant I ran the test case under the debugger, the problem went away.  Problems that disappear under the debugger are a classic symptom of a heisenbug, this was no exception.

If I attached the debugger AFTER the test started but before the failure hit, I was able to see the failure occur.  The problem only occurred when launching the app under the debugger.  At that point I realized what was happening.

As MSDN says

Processes that the debugger creates (also known as spawned processes) behave slightly differently than processes that the debugger does not create.

Instead of using the standard heap API, processes that the debugger creates use a special debug heap. On Microsoft Windows XP and later versions of Windows, you can force a spawned process to use the standard heap instead of the debug heap by using the _NO_DEBUG_HEAP environment variable or the -hd command-line option.

It turns out that I had added a member variable to a class and failed to initialize it in the constructor of the class.  When launched under the debugger, the debug heap initializes all allocated memory to a known value.  That means that when launched under the debugger the member variable had that known value, when launched without the debugger it was uninitialized and happened to have the value of 0.  For a number of reasons, this value caused the test to fail. 

 

I hate heisenbugs, but I like it when they’re really easy to find like this one.