有时我在使用 GCC(4.6.4,Ubuntu 12.04)时遇到一个奇怪的问题,我用它来编译一个巨大的项目(数百个文件和数十万行代码),但我最近发现了一些东西。在某些编译之后(似乎是随机发生的),我得到一段特定的代码以不同的方式和错误地编译,导致我的代码中出现未定义的行为:
class someDerivedClass : public someBaseClass
{
public:
struct anotherDerived : public anoterBaseClass
{
void SomeMethod()
{
someMember->someSetter(2);
}
}
}
Run Code Online (Sandbox Code Playgroud)
其中“someSetter”定义为:
void someSetter(varType varName) { someOtherMember = varName; }
Run Code Online (Sandbox Code Playgroud)
通常,SomeMethod() 被编译为:
00000000019fd910 mov 0x20(%rdi),%rax
00000000019fd914 movl $0x2,0x278c(%rax)
00000000019fd91e retq
Run Code Online (Sandbox Code Playgroud)
但有时它会(错误地)编译为:
000000000196e4ee mov 0x20(%rdi),%rax
000000000196e4f2 movl $0x2,0x27d4(%rax)
000000000196e4fc retq
Run Code Online (Sandbox Code Playgroud)
setter 似乎被内联了,可能是因为编译标志 -O2:
-std=c++11 -m64 -O2 -ggdb3 -pipe -Wliteral-suffix -fpermissive -fno-fast-math -fno-strength-reduce -fno-delete-null-pointer-checks -fno-strict-aliasing
Run Code Online (Sandbox Code Playgroud)
但这不是问题。真正的问题是成员someOtherMember的偏移量,0x278c是正确的(第一种情况),但0x27d4不正确(第二种情况),这显然最终会修改类中完全不同的成员。为什么会发生这种情况?我缺少什么?(另外,我不知道我可以发布哪些其他相关信息,所以询问)。请记住,当再次编译项目(完全重新编译或仅编译修改后的文件)而不修改受影响的文件(或具有所使用的类的文件)时,会发生这种情况。例如,仅在完全不相关的文件中的某处添加一个简单的 printf() 可能会触发此行为或使其在发生时消失。我应该把这归咎于 -O2 吗?如果没有优化标志,我无法重现它,因为这是完全随机发生的。我正在使用make -j 8,即使在清理构建文件夹后也会发生这种情况,但不一定仅在执行此操作后才会发生
正如评论中所述,您可能有一些东西在不同的 中以不同的方式限制您的类的定义.cpp,例如#pragma pack在包含您的 ; 之前的 a 或类似的东西.h。当链接器必须选择时,它可能会不确定地选择(因为它期望所有定义都相同)。
为了缩小对问题根源的搜索范围,我会这样做:
-g);gdb根据每个模块确定“有问题”字段的偏移量是多少gcc -E扩展所有预处理器内容并查找问题。作为步骤 2 的辅助,您可以使用此 bash 单行代码(在目标文件所在的目录中运行):
for i in ./*.o; do echo -n "$i: "; gdb -batch -q "$i" -ex "print &((YourClass*)0)->yourField"; done
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
395 次 |
| 最近记录: |