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: unassig...@gcc.gnu.org
        ReportedBy: richard-gccbugzi...@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.

Reply via email to