【问题标题】:Is there a way to detect inline function ODR violations?有没有办法检测内联函数 ODR 违规?
【发布时间】:2015-10-21 17:37:00
【问题描述】:

所以我在 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() 的两个实现完全不同,因此问题仍然没有被注意到,因此它们不会被编译成相同数量的指令。

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

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

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

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

【问题讨论】:

  • 我想知道在 .cpp 文件中包含 inline 函数的用例是什么。我想不出任何可能的优势。
  • @sjdowling 为什么是 inline 关键字?遗留代码。还要考虑这个:struct A { A(){} }; - 这里的构造函数是在结构定义内定义的,并且是隐式内联的。 2 个这样的结构可能具有相同的布局但不同的内联方法...
  • 在此遗留代码中查找这些 ODR 违规的最简单方法可能是从 .cpp 文件中定义的函数中删除所有 inline 说明符并检查任何导致的链接错误。
  • 我喜欢你如何使用“遗留”来表示“破碎”。这段代码从来没有是个好主意。

标签: c++ linker g++ linker-errors one-definition-rule


【解决方案1】:

工具不完善。

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

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

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

【讨论】:

    【解决方案2】:

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

    【讨论】:

    • 这是我目前解决此类问题的方法,但进行统一构建并不总是那么容易 - 大量遗留代码 + 匿名静态 + 预处理器。这也对静态库中的符号没有帮助。
    猜你喜欢
    • 2015-03-08
    • 2011-07-13
    • 2019-05-09
    • 1970-01-01
    • 2016-10-01
    • 1970-01-01
    • 2021-02-09
    • 2010-09-19
    • 1970-01-01
    相关资源
    最近更新 更多