执行静态对象的析构函数时崩溃

时间:2016-12-05 22:12:42

标签: c++ global-variables static-initialization one-definition-rule

有一个微妙的错误,在我们的软件中无法预测。

当全局析构函数执行时会发生这种情况。通常它是一个“双重自由”错误,但我也看到了其他的东西:NULL-ptr dereference,ptr取消引用一个没有分配任何地址,未对齐访问(因为指针有一个垃圾值),与之相关的问题一个腐败的堆栈......列表继续。

1 个答案:

答案 0 :(得分:1)

这些神秘的原因&难以重现错误:严重违反单一定义规则。

一点背景......

由于我有点迟来,这个软件使用-zmuldefs链接器标志进行链接,指示链接器忽略如下情况。然后它被迫选择它遇到的第一个定义(当然链接器警告也被忽略了):

$ cat /tmp/file1.cc
int x;
int main( int argc, char *argv[] ) { return x; }

$ cat /tmp/file2.cc
double x = 3.14159265358979;

$ gcc /tmp/file{2,1}.cc -o /tmp/test
/tmp/ccuTgbRy.o:(.bss+0x0): multiple definition of 'x'
/tmp/cchvHEav.o:(.data+0x0): first defined here
/usr/bin/ld: Warning: size of symbol 'x' changed from 8 in /tmp/ccYCIypE.o to 4 in /tmp/ccuTgbRy.o
collect2: error: ld returned 1 exit status

$ gcc /tmp/file{2,1}.cc -Wl,-zmuldefs -o /tmp/test
/usr/bin/ld: Warning: size of symbol 'x' changed from 8 in /tmp/ccWaeBBi.o to 4 in /tmp/ccSc9IiE.o

$ /tmp/test; echo $?
68

这与问题的关系

在遇到此问题时,我遇到了四种基本情况:

$ cat /tmp/file1.cc
double x;  // (1) If file2.cc is linked first it may end up on
           // a dword boundary causing misaligned accesses
           // when used as a double.

std::string mystring; // (2) If file2.cc is linked first, the actual size
                      // of the object is sizeof(char*) so
                      // std::string::string() will clobber memory
                      // after the pointer.

std::string another; // (3)
                     // file1.cc is compiled with -fPIC & put into a
                     // shared library
                     // file2.cc is NOT compiled with -fPIC & is put
                     // into an executable
                     // 
                     // This will cause a very subtle problem: the two
                     // strings share the same piece of memory, but
                     // the constructor will execute once during the executable's
                     // _init() and once for each shared library with its own
                     // variable "another" when their _init() executes.
                     // The destructor will also execute multiple times

$ cat /tmp/file2.cc
int x;
char *mystring;       // (4) Modifying through this ptr will cause undefined
                      // behavior when the other file's "mystring" is used
std::string another;

导致大小或对齐更改的那些应该报告为链接器警告,因此有人可能倾向于通过重命名有问题的变量(或其他)来解决问题。

但是,在以下情况下无法看到问题存在:

  • 对象大小相同(x定义为float / int& sizeof(float)== sizeof(int))
  • 多个库和/或可执行文件中存在有问题的变量(具有相同的大小和类型)

唯一可以确保您消除所有这些问题的解决方案:

  • 摆脱-zmuldefs
  • 确保所有声明都来自标题/包含标题所在的