18

所以我在 2 个独立的翻译单元中有这段代码:

// a.cpp
#include <stdio.h>
inline int func() { return 5; }
int proxy();
int main() { printf("%d", func() + proxy()); }

// b.cpp
inline int func() { return 6; }
int proxy() { return func(); }

正常编译时,结果为10. 当使用 -O3(内联)编译时,我得到11.

我显然违反了func().

当我开始将不同 dll 的源合并到更少的 dll 中时,它就出现了。

我努力了:

  • GCC 5.1 -Wodr(需要-flto
  • 黄金链接器-detect-odr-violations
  • ASAN_OPTIONS=detect_odr_violation=1在使用地址清理程序运行检测的二进制文件之前进行设置。

据推测,Asan 可以捕获其他 ODR 违规行为(具有不同类型的全局变量或类似的东西......)

这是一个非常讨厌的 C++ 问题,我很惊讶没有可靠的工具来检测它。

也许我误用了我尝试过的工具之一?或者有什么不同的工具可以做到这一点?

编辑

即使我做了两个func()完全不同的实现,这个问题仍然没有被注意到,所以它们不会被编译成相同数量的指令。

这也会影响在类体内定义的类方法——它们是隐式内联的。

// a.cpp
struct A { int data; A() : data(5){} };

// b.cpp
struct A { int data; A() : data(6){} };

之后有大量复制/粘贴 + 小修改的遗留代码是一种乐趣。

4

2 回答 2

6

工具不完善。

我认为 Gold 的检查只会在符号具有不同类型或不同大小时注意到,这在此处不正确(两个函数将编译为相同数量的指令,只是使用不同的立即值)。

我不确定为什么-Wodr在这里不起作用,但我认为它只适用于类型,而不适用于函数,即它会检测到类类型的两个冲突定义,T而不是你的func().

我对 ASan 的 ODR 检查一无所知。

于 2015-07-30T11:46:57.457 回答
5

检测此类问题的最简单方法是将所有函数复制到一个编译单元中(如果需要,临时创建一个)。然后,任何 C++ 编译器都将能够在编译该文件时检测和报告重复定义。

于 2015-07-30T11:54:17.783 回答