Hello
We encountered a strange access violation in an application we're
working on. I managed to distill the problem down to a dozen lines of
code and find the cause, which lies in the choice of runtime library,
not in the code itself. The bug, if it indeed is a bug, is
reproduceable.
Following are steps to reproduce the problem in VC++2008. We haven't
tried reproducing it under an older development environment yet.
1. Create a new empty Win32 Console Application project
2. Add a new CPP file to the project and paste the following code:
#include <sstream>
struct Test
{
~Test ()
{
std::stringstream s1;
}
} G_Test;
int main ()
{
std::stringstream s2;
}
3. Compile and run: should work
4. Open the project's properties, change the runtime lib from
multithreaded debug DLL (the default in VC++2008) to multithreaded
debug. So, from /MDd to /MTd.
5. Compile and run: you should get an access violation resulting from
Line 6 of my example (the instanciation of s1).
6. Comment out Line 11 (the instanciation of s2), recompile and run:
no more access violation.
The access violation happens during the destruction of G_Test, in
~Test, during the construction of s1. If you look at the call stack,
you'll notice the stringstream constructor makes a call that ends up
resulting in an access violation. The actual line of code that causes
the violation is in 'xlocale', and depends on the build (debug or
release) and the runtime (debug or release); it's always a call to
'widen', 'do_widen', or something similar. When looking at the
assembly, the application seems to be trying to read a function's
address from an invalid location (read access violation) just prior to
attempting to call that address.
We're thinking that something in the STL, or in Microsoft's
implementation of the STL in some of the VC++2008 runtimes, gives us
an undefined behavior when trying to instanciate a stream after an
application returns, but before the globals run out of scope (so
basically in the app's exit/doexit, after main() returns). The error
depends on whether or not another stream has been instanciated before
the app's termination or not (as demonstrated by commenting out the
instanciation of 's2' in my example). It would seem that the non-DLL
runtimes are trying to make a call to a function that has been
deaddressed, but the DLL runtimes make the call properly.
It's an easy enough problem for us to work around, but I'd like to
know if this is expected behavior coming from the STL in VC++2008, and
if I properly understood the cause of the problem. We do have a valid
reason for using a global in our application (it's a singleton
instance of our logging system), and we do know how to work around it
(make sure it gets deleted before our WinMain returns), but I wanted
to bring up this issue here in case it's an actual bug in VC++2008,
and not an unexpected behavior resulting from our misuse of the STL.
Maybe the STL cannot be used after an application's main function
returns? (I'm not sure if the STL has startup and cleanup code).
I'd appreciate any input -- apologies for the long post!
Alex