1
votes

I'm working on a Win32 application in C++ with Visual Studio 2010. When run in debug mode the application runs fine and closes properly upon exit. In release however, the program runs fine but upon application close there's an unhandled exception: Unhandled exception at 0x009C19F5 in Application.exe: 0xC0000005: Access violation reading location 0x00297628.

The debugger then breaks inside xlocale in std::local's destructor:

~locale() _THROW0()
{  // destroy the object
if (_Ptr != 0)
    _DELETE_CRT(_Ptr->_Decref()); // breaks here with unhandled exception
}

The above code is being run, I believe, after my main function returns and exit( 0 ) is called somewhere. Here's my callstack upon crash:

Application.exe!std::locale::~locale() Line 411 C++
Application.exe!doexit(int code, int quick, int retcaller) Line 567 C
Application.exe!exit(int code) Line 393 C
Application.exe!__tmainCRTStartup() Line 284    C
kernel32.dll!@BaseThreadInitThunk@12()  Unknown
ntdll.dll!___RtlUserThreadStart@8() Unknown
ntdll.dll!__RtlUserThreadStart@8()  Unknown

I'm using Microsoft's application verifier and I'm running _CrtCheckMemory( ); often to check for heap corruption and I don't see any detected in either debug or release mode. I'm also not messing with std::locale at all in any of my source.

I recently switched the solution's settings to use unicode by default instead of 256 one byte sized characters. However switching back and forth now between unicode and multi-byte settings doesn't seem to affect the crash on exit in release.

Does anyone have any idea what's going on?

2
UB somewhere probably.Seth Carnegie
Hmm, I'm having trouble figuring out a way to track down where the undefined behavior could be stemming from.RandyGaul
Do you have any global variables (or statics) that use stdio or iostreams or the like?John Zwinck
Yes actually, I have a custom Reflection system that makes use of global variables for registration. Some of them perform file serialization and take a reference to ostream or istream as parameters.RandyGaul
Check all pointer frobbing in your program, make sure everything is properly disposed of only when the last user is gone. I don't know if something like valgrind (tracks all allocations, and gives you a summary of inconsistencies on end) is available for Windows.vonbrand

2 Answers

0
votes

I've found the solution. There are some global variables calling new and I have new overloaded. When new is called for the first time a custom memory manager is constructed. This is fine, but on program close some objects destruct after the memory manager does. Order of destruction is what was causing the problems.

0
votes

Another possible cause of a crash with identical symptoms is caused by a behaviour described by this subtle note:

Overload 7 (i.e. locale(const locale& other, Facet* f)) is typically called with its second argument, f, obtained directly from a new-expression: the locale is responsible for calling the matching delete from its own destructor.

This seems like implying that the locale will delete the facet only if it came from new, but in practice it doesn't. In other words, a locale was constructed from a facet that was not constructed by new, or was deleted earlier, causing the crash on the locale destructor's delete.

This can be fixed either by giving the locale proper absolute ownership of the facet, i.e. not deleting the facet manually or letting any smart pointers do it automatically (as well as ensuring that it actually was constructed via new), or, if modifying the facet is possible, overloading delete.