views:

1087

answers:

3
  • environment: linux, userspace-application created via g++ from a couple of C++ files (result is an ELF)

  • there is a problem (SIGSEGV) when traversing the constructor list

    ( __CTOR_LIST__ )

(note: code called via this list is a kind of system initialisation for every class, not the constructor-code I wrote)

  • when I understand correctly every compilation unit (every .o created from a .cpp) creates one entry in
    __CTOR_LIST__ 
  • the problem (SIGSEGV) does not exist when I step via GDB through the program

  • for debugging this I'm looking for an way to add own code code before the call of

    "_do_global_ctors_aux"

any hints for this ?

thanks,

Uwe

+1  A: 

It's possible that you're being bitten by the so-called "Static Initialization Order Fiasco".

Basically, when there is more than one translation unit (that is, C++ source file), and each file defines a global object, it is not possible for the C++ compiler/linker to establish which to construct first. If x depends on y being constructed first, but by chance compilation/linking causes x to be constructed before y, the program will typically crash. See item [10.12] of the C++ FAQ Lite for more details. Item [10.13] contains a solution -- the "construct on first use" idiom.

j_random_hacker
+6  A: 

There are many possible reasons of this. Ranges from that you access objects not yet created (because order of creation of objects across different translation units is undefined) which i think is quite probable in this case, and ranges to an error on your build-environment.

To make a own function be called before other constructor function, you have a constructor (priority) attribute described here. GCC keeps a priority for each files' constructor input section. And it links them in order of those priorities. In the linker script of my linux system, that code looks like this (output it using ld -verbose):

  .ctors          :
  {
    /* gcc uses crtbegin.o to find the start of
       the constructors, so we make sure it is
       first.  Because this is a wildcard, it
       doesn't matter if the user does not
       actually link against crtbegin.o; the
       linker won't look for a file to match a
       wildcard.  The wildcard also means that it
       doesn't matter which directory crtbegin.o
       is in.  */
    KEEP (*crtbegin.o(.ctors))
    KEEP (*crtbegin?.o(.ctors))
    /* We don't want to include the .ctor section from
       the crtend.o file until after the sorted ctors.
       The .ctor section from the crtend file contains the
       end of ctors marker and it must be last */
    KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors))
    KEEP (*(SORT(.ctors.*)))
    KEEP (*(.ctors))
  }

You would want to give it a low priority to make it execute before other registered ctor functions having a higher priority number. However from the looks of it, it seems like constructors having no number will be executed first. Not sure entirely. Best you give it a try. If you want to have your function called even before _do_global_ctors_aux, you have to release the original _init function that is normally executed when your program is loaded by the ELF loader (look into the -init option of ld). It's been some time since i messed with it, but i remember it has to do some intimate details of initialization, so i wouldn't try to replace it. Try using the constructor attribute i linked to. However, be very careful. Your code will possibly be executed before other important objects like cout are constructed.

Update: I did a test, and it actually executes ctor functions in reverse. So ctor functions that are linked first are executed later. This code happens to be in crtstuff.c of the gcc source code:

  func_ptr *p;
  for (p = __CTOR_END__ - 1; *p != (func_ptr) -1; p--)
    (*p) ();

I made a little test:

void dothat() { }
struct f {
    f() { dothat(); }
} f_;
void doit() __attribute__((constructor (0)));
void doit() { }
int main() { }

Linking with --print-map yields, among others, this output:

.ctors          0x080494f4       0x10
 *crtbegin.o(.ctors)                 
 .ctors         0x080494f4        0x4 /usr/lib/gcc/i686-pc-linux-gnu/4.3.2/crtbegin.o
 *crtbegin?.o(.ctors)                                                                
 *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors)                                        
 .ctors         0x080494f8        0x4 /tmp/ccyzWBjs.o                                
 *(SORT(.ctors.*))                                                                   
 .ctors.65535   0x080494fc        0x4 /tmp/ccyzWBjs.o                                
 *(.ctors)                                                                           
 .ctors         0x08049500        0x4 /usr/lib/gcc/i686-pc-linux-gnu/4.3.2/crtend.o

Notice how .ctors.65535 is the section we implicitly created by our attribute priority 0. Now, if you give it that priority, gcc warns and it's totally right :p

test.cpp:7: warning: constructor priorities from 0 to 100 are reserved for the implementation

I tested it by breaking on doit and dothat, and it called them in the order we expect. Have fun!

Johannes Schaub - litb
A: 

Not the question you asked, but...

In C++/g++, you can have a class where the declared [header] methods are never actually defined in the source [.cc] files as long as those methods are never invoked.

As a consequence, you can copy your current code files to a temporary directory, do a hack and slash job on them, run a [manual] binary search, and isolate the problem fairly quickly.

Not elegant, but highly effective.


Aside from the infamous "Static Initialization Order" issue, there are also more esoteric cases such as the one recently pointed out to me here on SO by Charles Bailey (see the comments).

   E.g Mixing:  int p [] = { 1,2,3 };
          And:  extern int * p;

Will produce a similar coredump problem.

Mr.Ree