有没有办法检测内联函数 ODR 违规?
Is there a way to detect inline function ODR violations?
所以我在 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()
的 ODR。
当我开始将不同 dll 的源合并为更少的 dll 时,它出现了。
我试过:
- GCC 5.1
-Wodr
(需要 -flto
)
- 黄金链接器
-detect-odr-violations
- 在 运行 带有地址清理程序的检测二进制文件之前设置
ASAN_OPTIONS=detect_odr_violation=1
。
Asan 可以捕获其他 ODR 违规(具有不同类型或类似内容的全局变量...)
这是一个非常讨厌的 C++ 问题,我很惊讶没有可靠的工具来检测它。
也许我误用了我尝试过的工具之一?或者有不同的工具吗?
编辑:
即使我使 func()
的 2 个实现截然不同,因此它们不会被编译成相同数量的指令,问题仍然没有被注意到。
这也会影响在 class 体内定义的 class 方法 - 它们是隐式内联的。
// a.cpp
struct A { int data; A() : data(5){} };
// b.cpp
struct A { int data; A() : data(6){} };
遗留代码有很多 copy/paste + 之后的小修改是一种乐趣。
工具不完善。
我认为 Gold 的检查只会在符号具有不同类型或不同大小时注意到,这在这里不是真的(两个函数将编译为相同数量的指令,只是使用不同的立即值)。
我不确定为什么 -Wodr
在这里不起作用,但我认为它只适用于类型,而不适用于函数,即它会检测到 class 类型的两个相互冲突的定义 T
但不是你的 func()
.
我对ASan的ODR检查一无所知
检测此类问题的最简单方法是将所有函数复制到一个编译单元中(如果需要,临时创建一个)。然后,任何 C++ 编译器都能够在编译该文件时检测并报告重复定义。
所以我在 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()
的 ODR。
当我开始将不同 dll 的源合并为更少的 dll 时,它出现了。
我试过:
- GCC 5.1
-Wodr
(需要-flto
) - 黄金链接器
-detect-odr-violations
- 在 运行 带有地址清理程序的检测二进制文件之前设置
ASAN_OPTIONS=detect_odr_violation=1
。
Asan 可以捕获其他 ODR 违规(具有不同类型或类似内容的全局变量...)
这是一个非常讨厌的 C++ 问题,我很惊讶没有可靠的工具来检测它。
也许我误用了我尝试过的工具之一?或者有不同的工具吗?
编辑:
即使我使 func()
的 2 个实现截然不同,因此它们不会被编译成相同数量的指令,问题仍然没有被注意到。
这也会影响在 class 体内定义的 class 方法 - 它们是隐式内联的。
// a.cpp
struct A { int data; A() : data(5){} };
// b.cpp
struct A { int data; A() : data(6){} };
遗留代码有很多 copy/paste + 之后的小修改是一种乐趣。
工具不完善。
我认为 Gold 的检查只会在符号具有不同类型或不同大小时注意到,这在这里不是真的(两个函数将编译为相同数量的指令,只是使用不同的立即值)。
我不确定为什么 -Wodr
在这里不起作用,但我认为它只适用于类型,而不适用于函数,即它会检测到 class 类型的两个相互冲突的定义 T
但不是你的 func()
.
我对ASan的ODR检查一无所知
检测此类问题的最简单方法是将所有函数复制到一个编译单元中(如果需要,临时创建一个)。然后,任何 C++ 编译器都能够在编译该文件时检测并报告重复定义。