Can someone help understanding the following seg fautl, and also why it does work on changing the link order:
common.h file:
#include <set>
struct T {
explicit T(const char*) {
Instances.insert(this);
}
static std::set<T*> Instances;
};
d.cc file:
#include "common.h"
T d(__FILE__);
main.cc file:
#include "common.h"
#include <set>
#include <iostream>
/*static*/ std::set<T*> T::Instances;
int main() {
std::cout << "T::Instances.size() = " << T::Instances.size() << std::endl;
while(true);
}
Building and running with following commands:
g++ -c -g -Wall -Wextra d.cc -o d.o
g++ -c -g -Wall -Wextra main.cc -o main.o
g++ -g d.o main.o -o app
./app
Running the commands I get a seg fault, with the following backtrace:
$ ./app
Segmentation fault (core dumped)
$ gdb ./app
(gdb) run
Starting program: /home/meodou/zdev/poc_at_7405/testi/app
Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7afebca in std::local_Rb_tree_decrement (__x=0x6031e8 <T::Instances+8>) at ../../../../../libstdc++-v3/src/c++98/tree.cc:98
98 && __x->_M_parent->_M_parent == __x)
(gdb) bt
#0 0x00007ffff7afebca in std::local_Rb_tree_decrement (__x=0x6031e8 <T::Instances+8>) at ../../../../../libstdc++-v3/src/c++98/tree.cc:98
#1 0x0000000000401365 in std::_Rb_tree_iterator<T*>::operator-- (this=0x7fffffffdc50) at /usr/include/c++/5.3.1/bits/stl_tree.h:220
#2 0x000000000040102f in std::_Rb_tree<T*, T*, std::_Identity<T*>, std::less<T*>, std::allocator<T*> >::_M_get_insert_unique_pos (
this=0x6031e0 <T::Instances>, __k=@0x7fffffffde08: 0x6031d1 <d>) at /usr/include/c++/5.3.1/bits/stl_tree.h:1819
#3 0x0000000000400dfe in std::_Rb_tree<T*, T*, std::_Identity<T*>, std::less<T*>, std::allocator<T*> >::_M_insert_unique (this=0x6031e0 <T::Instances>,
__v=@0x7fffffffde08: 0x6031d1 <d>) at /usr/include/c++/5.3.1/bits/stl_tree.h:1863
#4 0x0000000000400d79 in std::set<T*, std::less<T*>, std::allocator<T*> >::insert (this=0x6031e0 <T::Instances>, __x=@0x7fffffffde08: 0x6031d1 <d>)
at /usr/include/c++/5.3.1/bits/stl_set.h:485
#5 0x0000000000400d47 in T::T (this=0x6031d1 <d>) at common.hh:6
#6 0x0000000000400ce0 in __static_initialization_and_destruction_0 (__initialize_p=1, __priority=65535) at d.cc:2
#7 0x0000000000400d0a in _GLOBAL__sub_I_d () at d.cc:2
#8 0x0000000000401b2d in __libc_csu_init ()
#9 0x00007ffff71a050f in __libc_start_main (main=0x40173b <main()>, argc=1, argv=0x7fffffffdf68, init=0x401ae0 <__libc_csu_init>, fini=<optimized out>,
rtld_fini=<optimized out>, stack_end=0x7fffffffdf58) at libc-start.c:245
#10 0x0000000000400bc9 in _start ()
So that something I m trying to understand. The second thing is that if I invert the linking order:
From g++ -g d.o main.o -o app
To g++ -g main.o d.o -o app
The program runs without seg fault.
$ g++ -c -g -Wall -Wextra d.cc -o d.o
$ g++ -c -g -Wall -Wextra main.cc -o main.o
$ g++ -g main.o d.o -o app
$ ./app
T::Instances.size() = 1
Any explanation what this is working? The problem seems to be related to global variables initialization but I still cannot see what is happening.
Using g++ (GCC) 5.3.1
BR,
...........................
In answer to Quentin comment: Yes I know that is should be related to static initialization but still I dont see really how this is happening. (I am not in the case of https://isocpp.org/wiki/faq/ctors#static-init-order where a compile unit is calling an object not initialized as it s found in another compile unit, at least not directly).
I can also add a T object the main.cc file:
#include <iostream>
/*static*/ std::set<T*> T::Instances;
+T main_obj(__FILE__);
int main() {
std::cout << "T::Instances.size() = " << T::Instances.size() << std::endl;
I ll still get a crash, here my understanding is that we are calling a static function on an object that we already have in current compile unit (should be correctly initialized). So we are not depending at least directly on the object found in d.cc file. Again I strongly believe that is related to static initialization but I dont clearly see the explanation of it. (The object that we are calling its static member should be already initialized)