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.

に対して ODR 違反を行ったことは明らかですfunc()

異なるdllのソースをより少ないdllにマージし始めたときに現れました。

私が試してみました:

  • GCC 5.1 -Wodr(必要-flto)
  • ゴールドリンカー-detect-odr-violations
  • ASAN_OPTIONS=detect_odr_violation=1アドレス サニタイザーを使用してインストルメント化されたバイナリを実行する前に設定します。

Asan は、他の ODR 違反をキャッチできると思われます (異なるタイプのグローバル変数またはそのようなもの...)

これは C++ の非常に厄介な問題であり、それを検出するための信頼できるツールがないことに驚いています。

おそらく、私が試したツールの 1 つを悪用したのでしょうか? または、これには別のツールがありますか?

編集

func()大幅に異なる 2 つの実装を作成しても、同じ量の命令にコンパイルされないため、問題に気付かないままです。

これは、クラス本体内で定義されたクラス メソッドにも影響します。それらは暗黙的にインライン化されます。

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

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

多くのコピー/貼り付けとその後の小さな変更を伴うレガシーコードは楽しいものです。

4

2 に答える 2

6

ツールは不完全です。

Gold のチェックは、シンボルの型やサイズが異なる場合にのみ気付くと思いますが、ここではそうではありません (両方の関数は、異なる即値を使用するだけで、同じ数の命令にコンパイルされます)。

ここで機能しない理由はわかり-Wodrませんが、関数ではなく型に対してのみ機能すると思います。つまり、クラス型の2つの競合する定義を検出しTますが、あなたのfunc().

ASan の ODR チェックについては何も知りません。

于 2015-07-30T11:46:57.457 に答える
5

このような問題を検出する最も簡単な方法は、すべての関数を単一のコンパイル単位にコピーすることです (必要に応じて一時的に作成します)。これにより、C++ コンパイラは、そのファイルをコンパイルするときに、重複した定義を検出して報告できるようになります。

于 2015-07-30T11:54:17.783 に答える