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

Re: VC++2008: STL access violation depending on runtime library being used -- bug or undefined behavior? by David

David
Wed Jul 09 17:30:31 CDT 2008

>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.

Yes, I can reproduce it as well Alex.

Can you submit a bug report on it at the MS connect web site, then
post a link to your bug report back here and I'll vote/validate it.

Thanks
Dave

Re: VC++2008: STL access violation depending on runtime library being used -- bug or undefined behavior? by Alan

Alan
Wed Jul 09 20:54:41 CDT 2008

"Alex" <alex.cote@cossette.com> wrote in message
news:d0419fb5-ef4a-43bd-a450-88a0b8131559@a1g2000hsb.googlegroups.com...
> 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;
> }

It's not a bug. The reason it works using the DLL version is because
std::stringstream is initialized when the DLL is loaded
(DLL_PROCESS_ATTACH), which is before the CRT startup code begins it's
initialization of your global variables. The writers of the DLL version of
the lib would have faced the same problems as you are, namely the random
nature of object construction/desruction at global (or static object at
function) scope. When you link statically it becomes *your* problem to deal
with the fact that your objects may construct before "theirs" and you have
zero control over the construction/destruction order for global variables as
far as I know (and I wish I knew for certain).

So declaring a global object containing references to other globals is
essentially "undefined behaviour", meaning "steer clear".

The trick of defining static objects at function scope (and returning
references to them) can help to control the ordering slightly, but only as
long as the object doesn't depend on any other "static function scope"
object(s). There's no way to tell who's going to die first if more than one
function references the same "static function scoped" object. It's easy to
construct examples of this random behaviour with two "function statics",
each depending on a third "function static", with the second referencing the
first. If the first is constructed, thus constructing the 3rd, and then the
second one is constructed, clearly the second one is set to destruct last.
This would be following the destruction first, which would follow the
destrution of the third (ie. constructed by and before the first) which it
depends on.

In any case, it's a hell of a mess to keep track of, so I have only 1 rule
(which I violate occasionally when I'm 100% sure of the ordering):

Rule: Never declare a global, or which refernces any global, or "static at
function scope" which refernces any "static at function scope" unless the
referenced object is a built-in type.

You may declare a "static at function scope" which references any global
however, with the provision that the global doesn't in turn reference a
"static at function scope".

- Alan Carre




Re: VC++2008: STL access violation depending on runtime library being used -- bug or undefined behavior? by Igor

Igor
Wed Jul 09 21:15:10 CDT 2008

"Alan Carre" <alan@twilightgames.com> wrote in message
news:OoCwo$i4IHA.1056@TK2MSFTNGP05.phx.gbl
> "Alex" <alex.cote@cossette.com> wrote in message
> news:d0419fb5-ef4a-43bd-a450-88a0b8131559@a1g2000hsb.googlegroups.com...
>> #include <sstream>
>> struct Test
>> {
>> ~Test ()
>> {
>> std::stringstream s1;
>> }
>> } G_Test;
>> int main ()
>> {
>> std::stringstream s2;
>> }
>
> So declaring a global object containing references to other globals is
> essentially "undefined behaviour", meaning "steer clear".

I don't see any global objects in the OP's code referencing any other
global objects. There's one global object, G_Test, and two local
variables.

Could you point to the rule in the C++ standard this code violates? I
can't think of any.
--
With best wishes,
Igor Tandetnik

With sufficient thrust, pigs fly just fine. However, this is not
necessarily a good idea. It is hard to be sure where they are going to
land, and it could be dangerous sitting under them as they fly
overhead. -- RFC 1925



Re: VC++2008: STL access violation depending on runtime library being used -- bug or undefined behavior? by Alan

Alan
Wed Jul 09 21:31:33 CDT 2008

Sorry, I wrote my example backwards and quickly and incorrectly.

I guess you'll have to trust me... It just so happens I had to unwind one of
these mixed up sequences a couple days ago and I was trying to reproduce the
sequence in my head and failed miserably ;-)

I think all you need are 2 "static function" objects to cause a crash.
Something like...

class Crasher
{
static ComplicatedObject& GetObject1() {static ComplicatedObject obj;
return obj;}
public:
Crasher() {GetObject1();}
~Crasher() {GetObject1();}
}

Crasher& func()
{
static Crasher crasher;
return crasher;
}

And that should do it!

'obj' is pushed onto the "destruct stack" after 'crasher' when we call func.
So 'obj' dies first, then 'crasher', and then we get our crash. And I would
double check and build a working example right now but I've got to get some
sleep!

Sorry about that... sleepiness can be as dangerous as globals!
- Alan Carre.




Re: VC++2008: STL access violation depending on runtime library being used -- bug or undefined behavior? by Alan

Alan
Wed Jul 09 21:50:17 CDT 2008

"Igor Tandetnik" <itandetnik@mvps.org> wrote in message
news:Ot%238JLj4IHA.4352@TK2MSFTNGP05.phx.gbl...
> I don't see any global objects in the OP's code referencing any other
> global objects. There's one global object, G_Test, and two local
> variables.

Sure, errno. There's a global in the OP but you can't actually see it. It's
not written in the post, but it's a global variable that's "in the program".

Others include the zillion globals used by the STL some of which will be
supporting variables for things such as std::stringstream.

I know this to be true because I use the STL extensively and if I declare a
global STL object and attempt to reference it in a global that gets
constructed before the STL global does, then I get a crash. For instance
std::list. If I declare a global list and somewhere else declare a global
object referencing that list, and my global object constructs before the
list does, and I use the list in the constructor of the class I get a crash.

And so do you.

It's trivial to construct examples. It's normal behaviour, which is why
people have invented things called "singletons". Which I won't go into now
because I must sleep.

> Could you point to the rule in the C++ standard this code violates? I
> can't think of any.

This code does not violate any rule in the C++ standard. Nor does this:

char* c = 0;
*c = 0;

But that doesn't make it correct.

- Alan Carre



Re: VC++2008: STL access violation depending on runtime library being used -- bug or undefined behavior? by Alan

Alan
Wed Jul 09 22:19:57 CDT 2008

"Igor Tandetnik" <itandetnik@mvps.org> wrote in message
news:Ot%238JLj4IHA.4352@TK2MSFTNGP05.phx.gbl...
> I don't see any global objects in the OP's code referencing any other
> global objects. There's one global object, G_Test, and two local
> variables.

Sorry, I should be more clear and more awake...

You are right, s1 and s2 are both local, but it doesn't change the general
idea of what I'm describing. Local, global, whatever... if you use something
before it's initialized you're asking for trouble.

These must be true:
A) The local variable s1 references supporting globals in the STL
*certainly* (I'm not going to look through that mess of code to find an
example, too tired).
B) s1 is constructed inside a global variable hence at _cinit (ie. before
main).
C) If s1 references an uninitialized STL global it may *at least* corrupt
it.
D) When the program terminates whatever corruption to any STL globals caused
by s1 could easily cause a crash at cleanup time.

And if you compile his code and step through the atexit code (the global
destruct walking part), I'm sure you'll see the crash is in some way related
to a global, initially referenced by std::stringstream s1. It may be that s2
is merely required to invoke the cleanup code of std::stringstream.

- Alan Carre



Re: VC++2008: STL access violation depending on runtime library being used -- bug or undefined behavior? by Igor

Igor
Wed Jul 09 23:18:55 CDT 2008

"Alan Carre" <alan@twilightgames.com> wrote in message
news:etG9sej4IHA.2348@TK2MSFTNGP06.phx.gbl
> "Igor Tandetnik" <itandetnik@mvps.org> wrote in message
> news:Ot%238JLj4IHA.4352@TK2MSFTNGP05.phx.gbl...
>> I don't see any global objects in the OP's code referencing any other
>> global objects. There's one global object, G_Test, and two local
>> variables.
>
> Sure, errno. There's a global in the OP but you can't actually see
> it. It's not written in the post, but it's a global variable that's
> "in the program".

I have no idea what this is supposed to mean. Variables that exist but
you can't see them? Are they in any way related to fairies?

> Others include the zillion globals used by the STL some of which will
> be supporting variables for things such as std::stringstream.

If STL implementation uses global variables internally, it's the
implementation's job to maintain them in a way that doesn't interfere
with valid programs. If it fails to do so, it's buggy. Which seems to be
the case here.

Consider for example the specification of cin, cout et al - global
objects that are mandated by the standard:

27.3/2 The objects are constructed, and the associations are established
at some time prior to or during first time an object of class
basic_ios<charT,traits>::Init is constructed, and in any case before the
body of main begins execution.264) The objects are not destroyed during
program execution.265)

Footnote 265: Constructors and destructors for static objects can access
these objects to read input from stdin or write output to stdout or
stderr.

http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#369
If a translation unit includes <iostream>, or explicitly constructs an
ios_base::Init object, these stream objects shall be constructed before
dynamic initialization of non-local objects defined later in that
translation unit.

> I know this to be true because I use the STL extensively and if I
> declare a global STL object and attempt to reference it in a global
> that gets constructed before the STL global does, then I get a crash.

Here you are talking about two global objects you yourself declare - not
some invisible objects allegedly introduced by the implementation. Yes,
the order of construction and destruction of global objects is (almost
always) undefined. It is in fact irrelevant that one or more of those
objects happen to be of a type defined by STL: the exact same problem
would occur for two global objects of user-defined types.

But again - the program we are discussing declares exactly one global
object. Everything you say is true, but it has no bearing on the problem
at hand.

>> Could you point to the rule in the C++ standard this code violates? I
>> can't think of any.
>
> This code does not violate any rule in the C++ standard. Nor does
> this:
> char* c = 0;
> *c = 0;

Does too.

5.17/1 There are several assignment operators, all of which group
right-to-left. All require a modifiable lvalue as their left operand...
3.10/14 If an expression can be used to modify the object to which it
refers, the expression is called modifiable. A program that attempts to
modify an object through a nonmodifiable lvalue or rvalue expression is
ill-formed.

An expression *c where c is a null pointer doesn't refer to any object,
and thus is not a modifiable lvalue, and hence cannot appear on the left
hand side of an assignment operator.

See also

http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#232

--
With best wishes,
Igor Tandetnik

With sufficient thrust, pigs fly just fine. However, this is not
necessarily a good idea. It is hard to be sure where they are going to
land, and it could be dangerous sitting under them as they fly
overhead. -- RFC 1925



Re: VC++2008: STL access violation depending on runtime library being used -- bug or undefined behavior? by Igor

Igor
Wed Jul 09 23:29:39 CDT 2008

"Alan Carre" <alan@twilightgames.com> wrote in message
news:e0lkRvj4IHA.3484@TK2MSFTNGP05.phx.gbl
> "Igor Tandetnik" <itandetnik@mvps.org> wrote in message
> news:Ot%238JLj4IHA.4352@TK2MSFTNGP05.phx.gbl...
>> I don't see any global objects in the OP's code referencing any other
>> global objects. There's one global object, G_Test, and two local
>> variables.
>
> Sorry, I should be more clear and more awake...
>
> You are right, s1 and s2 are both local, but it doesn't change the
> general idea of what I'm describing.

Of course not. What you are describing is perfectly correct - it just
doesn't in any way apply to the problem we are discussing.

> Local, global, whatever... if
> you use something before it's initialized you're asking for trouble.

Quite. Now, where exactly does the OP's program use something before
it's initialized?

> These must be true:
> A) The local variable s1 references supporting globals in the STL
> *certainly* (I'm not going to look through that mess of code to find
> an example, too tired).

Well, if there's something deep inside an STL implementation that makes
a standard-conforming program not work, then it's a bug in the
implementation, not in the program.

> B) s1 is constructed inside a global variable hence at _cinit (ie.
> before main).

I'm not sure what you mean by "inside a variable". I'm not familiar with
the term.

s1 is declared as a local variable inside Test's _destructor_. It is
constructed and then destroyed within ~Test. Naturally, ~Test runs after
main, not before.

> C) If s1 references an uninitialized STL global it may *at least*
> corrupt it.

If such a global exists within the implementation, the implementation is
buggy.

> D) When the program terminates whatever corruption to any STL globals
> caused by s1 could easily cause a crash at cleanup time.
>
> And if you compile his code and step through the atexit code (the
> global destruct walking part), I'm sure you'll see the crash is in
> some way related to a global, initially referenced by
> std::stringstream s1. It may be that s2 is merely required to invoke
> the cleanup code of std::stringstream.

No doubt. But none of that proves that the program is invalid.
--
With best wishes,
Igor Tandetnik

With sufficient thrust, pigs fly just fine. However, this is not
necessarily a good idea. It is hard to be sure where they are going to
land, and it could be dangerous sitting under them as they fly
overhead. -- RFC 1925



Re: VC++2008: STL access violation depending on runtime library being used -- bug or undefined behavior? by Igor

Igor
Wed Jul 09 23:38:33 CDT 2008

"Alan Carre" <alan@twilightgames.com> wrote in message
news:%23TOIPUj4IHA.4908@TK2MSFTNGP04.phx.gbl
> Sorry, I wrote my example backwards and quickly and incorrectly.
>
> I guess you'll have to trust me... It just so happens I had to unwind
> one of these mixed up sequences a couple days ago and I was trying to
> reproduce the sequence in my head and failed miserably ;-)

I fully believe that the program does indeed crash the way the OP
describes. I have no reason to doubt his statement, nor yours.

However, I disagree with your claim that there's no bug in the STL
implementation, but the program itself is at fault. As far as I can
tell, the program is perfectly valid and C++-standard-conformant, and
the blame for its misbehavior lies squarely on the implementation.

> I think all you need are 2 "static function" objects to cause a crash.
> Something like...
>
> class Crasher
> {
> static ComplicatedObject& GetObject1() {static ComplicatedObject
> obj; return obj;}
> public:
> Crasher() {GetObject1();}
> ~Crasher() {GetObject1();}
> }
>
> Crasher& func()
> {
> static Crasher crasher;
> return crasher;
> }
>
> And that should do it!

Of course. But I fail to see how this is relevant to the original
program we are discussing. That program declares only one global object,
and doesn't reference any others.
--
With best wishes,
Igor Tandetnik

With sufficient thrust, pigs fly just fine. However, this is not
necessarily a good idea. It is hard to be sure where they are going to
land, and it could be dangerous sitting under them as they fly
overhead. -- RFC 1925



Re: VC++2008: STL access violation depending on runtime library being by Alex

Alex
Thu Jul 10 10:15:11 CDT 2008

Thanks for the contributions! I posted a bug report on Microsoft
Connect, as the issue seems likely to be an actual bug with their
implementation of the STL.

You can find the bug report here:
https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=355711

Re: VC++2008: STL access violation depending on runtime library being by Hendrik

Hendrik
Thu Jul 10 10:28:52 CDT 2008

Alex wrote:
> [...]
> I'd appreciate any input -- apologies for the long post!

It doesn't look like a similar scenario, but you might want to
have a look at this:
http://groups.google.com/group/microsoft.public.vc.stl/msg/8638bd6e63faaef3

> Alex

Schobi