gcc linker extension __attribute__((constructor)) causes crash in main()

656 Views Asked by At

First I've a singleton.cpp file to build a singleton object, and declare instance using attribute((constructor))

#include<iostream>
using namespace std;
class singleton{
public:
    singleton(){cout<<"singleton ctor\n";}
};
__attribute__((constructor)) static void beforeFunction()
{
    printf("beforeFunction\n");
    singleton obj;
}

And a simple main.cpp

#include<iostream>
using namespace std;
int main(){
    return 0;
}

I build main.cpp singleton.cpp together:

g++ singleton.cpp main.cpp -o main

./main
beforeFunction
Segmentation fault

So why my program crashes, what happened? How to fix it? I'm using gcc on ubuntu. Thanks a lot.

3

There are 3 best solutions below

1
On BEST ANSWER

I reproduced this with g++ (Debian 7.3.0-5), and also g++ (GCC) 9.0.0 20180902 (experimental).

It's interesting that this fails:

$ g++ singleton.cpp main.cpp && ./a.out
beforeFunction
Segmentation fault

but this works as expected:

$ g++ main.cpp singleton.cpp && ./a.out
beforeFunction
singleton ctor

As Acorn correctly stated, the iostream / std::cout machinery has not been properly initialized by the time you called singleton constructor. This is happening because there is special code emitted into main.o (and only main.o) which calls std::ios_base::Init::Init(). And only because main.cpp has extraneous #include <iostream>.

How to fix it?

The best fix is to not use __attribute__((constructor)) at all. In your case, there is no reason to do what you are doing. Do this instead:

// singleton2.cpp
#include<iostream>
using namespace std;

class singleton{
  public:
    singleton(){cout<<"singleton ctor\n";}
};

static singleton obj;

With above code, either order of linking works:

$ g++ main.cpp singleton2.cpp && ./a.out
singleton ctor

$ g++ singleton2.cpp main.cpp && ./a.out
singleton ctor

If you insist on using __attribute__((constructor)), then make sure main.o is on your link line before any other object that could use iostreams.

0
On

std::cout is initialized with the help of a static C++ object, see <iostream>:

  // For construction of filebuffers for cout, cin, cerr, clog et. al.
  static ios_base::Init __ioinit;

Since your code relies both on this static constructor and has an ELF constructor, it runs into this GCC limitation:

However, at present, the order in which constructors for C++ objects with static storage duration and functions decorated with attribute constructor are invoked is unspecified.

If you use a C++ object instead, the order is well-defined. The GCC manual also suggests to use the init_priority attribute, but since you cannot apply it to the definition of __ioinit (except through preprocessor hackery), I do not think this is helpful in this context.

0
On

So why my program crashes, what happened?

Most likely, the iostream machinary is not initialized yet at the time the __attribute__((constructor)) functions are run.

How to fix it?

Either use C I/O like printf, which seems to work in your case; or better, avoid using __attribute__((constructor)) altogether (it is not standard C nor C++, i.e. it makes your program non-portable).

Note that there is no need for __attribute__((constructor)) to create singletons or global objects.