This is the mail archive of the
gcc-bugs@gcc.gnu.org
mailing list for the GCC project.
[Bug c++/50986] New: weak static data members with constant initializers emitted in .rodata, leading to segfault on startup
- From: "richard-gccbugzilla at metafoo dot co.uk" <gcc-bugzilla at gcc dot gnu dot org>
- To: gcc-bugs at gcc dot gnu dot org
- Date: Thu, 03 Nov 2011 18:40:29 +0000
- Subject: [Bug c++/50986] New: weak static data members with constant initializers emitted in .rodata, leading to segfault on startup
- Auto-submitted: auto-generated
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=50986
Bug #: 50986
Summary: weak static data members with constant initializers
emitted in .rodata, leading to segfault on startup
Classification: Unclassified
Product: gcc
Version: 4.6.3
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: c++
AssignedTo: unassigned@gcc.gnu.org
ReportedBy: richard-gccbugzilla@metafoo.co.uk
It's possible for a weak variable K (either a static data member of a class
template or a static variable in an inline function) to have a constant
initializer in one translation unit (call it TU1) and a non-constant
initializer in another translation unit (call it TU2), without an ODR
violation. This can happen, for instance, if the initializer for an extern
const int X whose value is used in K's initializer is visible in one TU but not
the other.
In this case, in TU1, g++ uses static initialization and puts the variable in
.rodata. In TU2, it uses dynamic initialization. If these TUs are linked
together in the wrong order, the linker will put the variable in .rodata but
the binary will still try to dynamically initialize it. This causes the program
to segfault on startup (trying to write to read-only memory).
Testcase:
$ cat repro.cpp
struct S {
static const int x;
};
template<typename T> struct U {
static const int k;
};
#ifdef TU1
const int S::x = 42;
#endif
template<typename T> const int U<T>::k = T::x;
#ifdef TU1
extern const int *f();
const int *g() { return &U<S>::k; }
int main() {
return *f() + U<S>::k;
}
#endif
#ifdef TU2
const int *f() { return &U<S>::k; }
#endif
$ g++ repro.cpp -DTU1 -c -o tu1.o
$ g++ repro.cpp -DTU2 -c -o tu2.o
$ g++ tu1.o tu2.o
$ ./a.out
Segmentation fault
clang has the same issue (which is how this was discovered), and the current
proposed solution there is to never put weak constants in .rodata.