I get a segfault in my application and have been poking at it for multiple hours now. I was analysing the backtrace using gdb and noticed the following:
(gdb) frame 3
(gdb) info address C_STATIC_STRING
Symbol "C_STATIC_STRING" is static storage at address 0x66a660.
(gdb) frame 2
(gdb) info address C_STATIC_STRING
Symbol "C_STATIC_STRING" is static storage at address 0x66b800.
Above there are 2 stack frames referring to the same const string C_STATIC_STRING
in the same header file, but one frame correctly addresses the variable (frame 3) and the other (frame 2) has an offset address (by 4512 bytes if I calculated correctly).
- The 0x66a660 one addresses the correct string
- The 0x66b800 results in error if read: Cannot access memory at address 0xffffffffffffffe8
g++ (GCC) 4.8.5 20150623 (Red Hat 4.8.5-39.0.3)
ADDITIONAL INFO:
I have managed to reproduce the issue using a simpler code:
- constants.h - containing the macro and the constatnt
#ifndef CONSTANTS_H
#define CONSTANTS_H
using namespace std;
#include <iostream>
#include <string>
#ifndef C_MACRO
#define C_MACRO "MACRO "
#endif
const std::string CONSTANT = C_MACRO "CONSTANT_STRING";
#endif
- Test1 class - has a private string that it initializes during construction using the CONSTANT test1.h
#ifndef TEST1_H
#define TEST1_H
using namespace std;
#include <iostream>
#include <string>
#include "constants.h"
class Test1 {
public:
Test1();
std::string getString() {
return m_str;
}
private:
std::string m_str;
};
#endif
test1.cpp
using namespace std;
#include <iostream>
#include <string>
#include "test1.h"
Test1::Test1(): m_str(std::string("Extra ") + CONSTANT)
{
};
- Test class - owns an instance of Test1 test.h
#ifndef TEST_H
#define TEST_H
using namespace std;
#include <iostream>
#include <string>
#include "test1.h"
#include "constants.h"
class Test {
public:
Test1 getTest() {
return m_test;
}
private:
Test1 m_test;
};
#endif
test.cpp - pretty much empty
using namespace std;
#include <iostream>
#include <string>
#include "test.h"
- main.cpp -- has a static instance of Test class
using namespace std;
#include <iostream>
#include <string>
#include "test.h"
namespace NOTSTD {
Test variable;
}
using namespace NOTSTD;
int main()
{
std::cout << variable.getTest().getString() << " printed";
}
Now the build process
- Makefile
#Test makefile
CPP = g++
CPPFLAGS = -Wall -ggdb -O0
AR = ar
RANLIB = ranlib
OUTPUT = test
all:: $(OUTPUT)
for_static = test1.o
static_lib.a: $(for_static)
$(AR) qc $@ $(for_static)
$(RANLIB) $@
$(OUTPUT): static_lib.a test.o main.o
$(CPP) ${CPPFLAGS} test.o main.o -o $(OUTPUT) static_lib.a
%.o : %.cpp
$(CPP) $(CPPFLAGS) -c $< -o $@
clean:
rm -f $(OUTPUT)
rm -f *.o
rm -f *.a
Test1 gets compiled into a static library and later used to compile the rest. In Cygwin, it works as expected On OEL 7 it gets a segmentation fault (no matter the optimization level) If I omit the statically linked library and just compile in test1, then it works on OEL too.
Disassembly seems to indicate that the issue lies with initialization order of static variables/constants.
I'm not too good at C++ and compilers. Perhaps anyone has an idea on what is exactly going on? GCC bug or is it just me?