I have a small single-threaded C++ application, compiled and linked using Visual Studio 2005, that uses boost (crc, program_options, and tokenizer), a smattering of STL, and assorted other system headers.
(It's primary purpose is to read in a .csv and generate a custom binary .dat and a paired .h declaring structures that "explain" the format of the .dat.)
The tool is crashing (access violation on NULL) when run outside the debugger, only in release. E.g. pressing F5 does not cause the tool to crash, Ctrl-F5 does. When I re-attach the debugger, I get this stack:
ntdll.dll!_RtlAllocateHeap@12() + 0x26916 bytes
csv2bin.exe!malloc(unsigned int size=0x00000014) Line 163 + 0x63 bytes C
csv2bin.exe!operator new(unsigned int size=0x00000014) Line 59 + 0x8 bytes C++
>csv2bin.exe!Record::addField(const char * string=0x0034aac8) Line 62 + 0x7 bytes C++
csv2bin.exe!main(int argc=0x00000007, char * * argv=0x00343998) Line 253 C++
csv2bin.exe!__tmainCRTStartup() Line 327 + 0x12 bytes C
The line it's crashing on is a somewhat innocuous-looking allocation:
pField = new NumberField(this, static_cast<NumberFieldInfo*>(pFieldInfo));
...I don't believe it has reached the constructor yet, it's just allocating memory before jumping to the constructor. It has also executed this code dozens of times by the time it crashes, usually in a consistent (but otherwise non-suspicious) location.
The problem goes away when compiling with /MTd or /MDd (debug runtime), and comes back when using /MT or /MD.
The NULL is loaded from the stack, and I can see it in memory view. _RtlAllocateHeap@12 + 0x26916 bytes seems like a huge offset, like an incorrect jump has been made.
I've tried _HAS_ITERATOR_DEBUGGING
in a debug build and that hasn't brought up anything suspicious.
Dropping a HeapValidate at the beginning and end of Record::addField shows an OK heap right up to when it crashes.
This used to work -- I'm not entirely sure what changed between now and the last time we compiled the tool (probably years ago, maybe under an older VS). We've tried an older version of boost (1.36 vs 1.38).
Before dropping back to manual investigation of the code or feeding this to PC-Lint and combing through its output, any suggestions on how to effectively debug this?
[I'll be happy to update the question with more info, if you request info in the comments.]