有一个微妙的错误在我们软件的一部分中无法预见。
当全局驱动器执行时,它会发生。通常这是一个"双重"错误,但我也看到了其他事情:null-ptr取消,PTR解释对任何没有分配的地址,未分配的访问权限(因为指针具有垃圾价值),与之相关的问题损坏的堆栈...列表继续。
这些神秘的原因&难以复制错误:对一个定义规则的微妙违反。
一点背景...
由于我有点tike,因此使用-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))
- 在多个库中存在有问题的变量(具有相同大小的尺寸& type)和/或可行者
唯一可以确保您消除所有这些问题的解决方案:
- 摆脱
-zmuldefs
- 确保所有声明都来自标题/包括定义的标题