2010-12-28 8 views
0

GCCリンカは、2つのファイルで1つの変数が定義されていることを気にしません。私はこれが第三者の図書館が私たちを引き起こしているトラブルの原因だと思う。共有ライブラリの変数の重複定義を検出する

これを持っ:

ファイルa.cppが含まれています

int foo; 
//do things with it. 

ファイルb.cppが含まれています

int foo; 
//do other things with it. 

ファイルc.cppが含まれています

extern int foo; 
//do other things with it. 

それらはすべてgccによってコンパイルされます.oファイルを共有オブジェクトとしてリンクします。

gcc -fPIC -c a.cpp 
gcc -fPIC -c b.cpp 
gcc -fPIC -c c.cpp 
ld *.o -shared -soname,mylib -o mylib 

リンカーは、まったく文句を言いませんが、結果として生じるバイナリは正しくありません。私たちは、少なくともこの種の紛争がいくつかあり、それを見つけたいと思っています。どのような種類のリンカーオプションで検出できますか?

(興味深いことに、両方のファイルで変数が初期化されている場合(int foo=0)、エラーが発生します)。

答えて

0

コンパイラオプション-fno-commonは、すべての変数を強制的に初期化するので、リンク時にエラーが発生します。

1

今すぐお持ちください - 2つのファイルで2つの異なる目的でfooを使用していますか?これは確かにランタイムエラーにつながるでしょう。 fooがグローバルである必要がある場合、リンカーはそれを受け入れるかもしれませんが、あなたはfooのコピーを1つだけ取得します。グローバルにする必要がない場合は、 'static int foo;'と宣言する必要があります。

+0

私は同意していることが多く、はいです。時には原作者の動機を理解することで頭が痛む。ときには、静的であることが必要な場合もあれば、場合によってはexternであることもあります。 –

1

これはgcc/ldの重大な設計上のバグです.MSVCを使用しても発生しません。それはプログラムをリンクすることはなく、共有ライブラリのみが発生します。プログラムをリンクすると、リンカーは少なくともリンク時にすべての外部参照が満たされていることを保証します。共有ライブラリをリンクすると、共有ライブラリはリンクしません。代わりに、定義が存在しない外部参照はちょうど残っています。引数(ld manページで与えられます)は、シンボルがロード時に動的に解決されなければならないということです。実行可能ファイルからシンボルを取得する共有ライブラリの愚かな機能を使用するのも難しいです。

あなたのプログラムは不正行為をしません。ライブラリーのシンボルがロード時に満たされなければならない場合は、読み込み時間エラーが発生します。レイジーリンケージを指定すると、エラーは発生しますが、シンボル(AFAIK!)の最初の使用時にのみ発生します。

古いOSの中には、例えばBSDのように、不十分な外部ポインタをNULLとして残して、シンボルがリンクされているかどうかを調べるための "プログラム内"チェックを書くことができると思っています。 Linuxは少なくともこのAFAIKをサポートしていません。

共有ライブラリの外部参照を強制的に実行するためのリンカースイッチがありますが、ポータブルビルドで正しく使用するのは難しいです。プロセッサ用のスタートアップライブラリを明示的にリンクする必要があるからです。

私はこれを非常に深刻な設計バグとみなし、バグレポートを提出しようとしました。私自身の製品ではCygwinのもとでビルドすることができて嬉しかった。なぜなら、この挙動を許さないMSVCリンカを使用すると、このように私のコードでかなりのバグが見つかったからです。

+0

実際、あなたが書いていることは、私たちが持っていた別の問題です(しかし、少なくともそれらのことを警告するために何らかの方法でコンパイラを得ました)。あなたは 'extern int x;'のような状況を意味します。 ;これまで実行時に参照されていた場合、その定義は見つかりませんでした。これは異なっています: 'extern int x;'と複数の 'int x;'があります。 –

関連する問題