[英]gcc, segfault, and the mystery of the changing address of a static variable (across stack frames)
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 分析回溯并注意到以下几点:
(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).上面有 2 个堆栈帧在同一个头文件中引用相同的const string C_STATIC_STRING
,但是一个帧正确地寻址了变量(帧 3),另一个(帧 2)有一个偏移地址(如果我计算正确,则为 4512 字节) .
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:我设法使用更简单的代码重现了这个问题:
#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
#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测试1.cpp
using namespace std;
#include <iostream>
#include <string>
#include "test1.h"
Test1::Test1(): m_str(std::string("Extra ") + CONSTANT)
{
};
#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 test.cpp - 几乎是空的
using namespace std;
#include <iostream>
#include <string>
#include "test.h"
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现在的构建过程
#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. Test1 被编译成一个静态库,然后用于编译其余部分。 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.在 Cygwin 中,它按预期工作在 OEL 7 上它会出现分段错误(无论优化级别如何)如果我省略静态链接库并只在 test1 中编译,那么它也适用于 OEL。
Disassembly seems to indicate that the issue lies with initialization order of static variables/constants.反汇编似乎表明问题在于静态变量/常量的初始化顺序。
I'm not too good at C++ and compilers.我不太擅长 C++ 和编译器。 Perhaps anyone has an idea on what is exactly going on?也许有人知道到底发生了什么? GCC bug or is it just me? GCC错误还是只是我?
I would like to summarize the things I learned from the helpful comments above:我想总结一下我从上面有用的评论中学到的东西:
To work around the issue nr 2, I have wrapped my static variable in a method (a getter of sorts) and used the method instead of the variable.为了解决第 2 号问题,我将静态变量包装在一个方法(某种 getter)中,并使用该方法而不是变量。 It forces the initialization of other static variables at the correct time.它强制在正确的时间初始化其他静态变量。 the method looks something like that:该方法看起来像这样:
Test getTest(){
static Test test;
return test;
}
Would like to thank David Schwartz and n.'pronouns'm for their guidance.感谢 David Schwartz 和 n.'pronouns'm 的指导。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.