This is the mail archive of the libstdc++@gcc.gnu.org mailing list for the libstdc++ project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: Possible C++ bug: construction/destruction of global objects


In article <3E6E49A5 dot 6070802 at riverside-machines dot com> on gcc-bugs,
Evan Lavelle writes:
> Is this a bug? Basically, if I declare more than one object of type 
> 'wibble' at global scope (ie. 'foo1' and 'foo2' below), and 'wibble' has 
> a string constructor parameter, and the 'wibble' constructor calls 
> exit(), then I get a SIGSEGV during the exit(). This happens before 
> main() is called. Note that the code works (ie. the exit() completes 
> without a problem) if I declare only one 'wibble' object.

I have two answers.  The first is for users that want to construct
portable software (not entirely related to g++).  The second is an
analysis of the actual failure which might expose a bug in our
implementation (and might be of interest to C++ ABI hackers).

(1) I'm giving you an unofficial portability answer without my
libstdc++-v3 maintainer hat on:

If there is a clause in the standard that addresses this exact point,
then I don't know it offhand.  I'm fairly sure the C standard is
silent on the matter of exit() being called before main().  It just
wasn't on the radar.  BTW, if there were a bug w.r.t. ISO-C++-14882,
our current implementations strategy (layer on the system's libc where
possible) makes it very hard for us to fix it.

My usual advise is this (refined from the last time I posted such
based on feedback from Martin Sebor):

If you must have global C++ objects (and they are quite useful in some
situations), audit them to ensure that they don't directly or
indirectly use stateful libc functions (i.e. memcpy OK, setenv/exit
not OK).  No, I will not attempt to give a complete list.  My best
advice is to write your systems in a manner that avoids global objects
or only uses classes related to global objects with completely visible
implementations.  This advice is completely subjective and based on
personal experience.

(2) Now, I actually ran your testcase under the debugger.  It might be
a bug we could actually fix w.r.t. to some exit() implementations
depending on what the C++ ABI we use says to do (i.e. there might be
no way to properly record required information).  The root failure of
your test case in my environment is calling the destructor for an
object before the related constructor was called!  Here is the
modified test case:

#include <iostream>
#include <cstdlib>

struct wibble {
    int i;
    wibble(int a) : i(a) {
	std::cout << "exiting:" << a << std::endl;
	std::exit(1);
    }
    ~wibble() { std::cout << "~wibble:" << i << std::endl; }
};

wibble foo1(1);
wibble foo2(2);

int main() {
    std::cout << "Shouldn't get this far" << std::endl;
}

It prints (on ELF/dwarf and/or ports using init/fini section model):

exiting:1
~wibble:0
~wibble:1

If a standard says or strongly implies that exit() should be callable
in a global constructor, we have a bug traceable back to gcc circa 2.95.

Regards,
Loren


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]