Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Static order initialization fiasco, iostream and C++11

According to C++11 specification:

The results of including <iostream> in a translation unit shall be as if <iostream> defined an instance of ios_base::Init with static storage duration. Similarly, the entire program shall behave as if there were at least one instance of ios_base::Init with static storage duration

This implies that if my code looks like that:

// A.cpp
#include <iostream>
using namespace std;
unsigned long foo() {
    cerr << "bar"; 
    return 42;
}

and

// B.cpp

using namespace std;
extern unsigned long foo();

namespace {
unsigned long test() {
    int id = foo();
    return id;
}

unsigned long id = test();
}


int main() {
     return 0;
}

then I should be safe calling cerr without the risk of a static initialization fiasco.

Unfortunately, that code segfaults... Why? I don't think gcc 6.2.1 decided to ignore the C++11 specification, and I included <iostream> in A.cpp. According to the specification it should suffice.

like image 872
marmistrz Avatar asked Oct 20 '16 16:10

marmistrz


1 Answers

The full quote of the paragraph includes:

The objects are constructed and the associations are established at some time prior to or during the first time an object of class ios_base::Init is constructed, and in any case before the body of main begins execution. 293)

And with the footnote

293) If it is possible for them to do so, implementations are encouraged to initialize the objects earlier than required.

So, the guarantee is that the iostreams will work at the latest when entering main. There is no strict requirement that they should work earlier, unless the translation unit includes <iostream>.

You have found a way to circumvent this!

When calling foo() from B.cpp, the ios_base::Init instance included in A.cpp may, or may not, have been initialized.

like image 110
Bo Persson Avatar answered Oct 14 '22 00:10

Bo Persson