C標準によれば、プログラムが予約済み識別子を定義または宣言する場合、動作は未定義です。予約済み識別子の1つのカテゴリは、C標準ライブラリで定義された外部リンケージを持つ識別子です。
未定義の動作を持つプログラムの例として、次のことを考慮してください。file1.cは、time.hで宣言された標準ライブラリの関数time
と競合する外部リンケージで名前が付けられた変数を定義します。time
file1.c:
int time;
int foo( void )
{
return time;
}
file2.c:
#include <time.h>
#include <stdio.h>
extern int foo( void );
int main( void )
{
foo();
printf( "current time = %ld\n", time( NULL ) );
return 0;
}
プログラムをコンパイルして実行すると、time
file2.cで参照されているシンボルtime
が、Cライブラリの関数ではなく、file1.cの変数にリンクされるため、セグメンテーション違反が発生します。
$ gcc -c -o file1.o file1.c
$ gcc -c -o file2.o file2.c
$ gcc -o test file1.o file2.o
$ ./test
Segmentation fault (core dumped)
コンパイル時またはリンク時に、GCCがユーザーコード内の競合する予約済み識別子の使用を検出する方法があるかどうか疑問に思っています。私の動機は次のとおりです。ユーザーがアプリケーションにC拡張機能を記述して、コンパイルしてアプリケーションの残りの部分にリンクできるアプリケーションに取り組んでいます。ユーザーのCコードが上記の例のように予約済みの識別子を使用している場合、結果のプログラムは予測が難しい方法で失敗する可能性があります。
頭に浮かぶ解決策の1つはnm
、ユーザーのオブジェクトファイルでのようなものを実行し、定義されたシンボルをCライブラリの予約済み識別子のリストと比較することです。ただし、GCCで問題を検出できるものを見つけたいと思っています。誰かがそれが可能かどうか知っていますか、または何か提案がありますか?
静的にリンクできるlibc実装を取得-Wl,--whole-archive
して、オブジェクトファイルにスラップすることができます。
main.c:
int time=42;
int main(){}
それをlibc全体とリンクします:
$ musl-gcc main.c -static -Wl,--whole-archive
複数の定義エラーが発生した場合、またはシンボルのタイプ/サイズ/配置が変更されたという警告が表示された場合は、libcと衝突しています。
/usr/local/bin/ld: /usr/local/musl/lib/libc.a(time.lo): in function `time':
/home/petr/f/proj/bxdeps/musl/src/time/time.c:5: multiple definition of `time'; /tmp/cc3bL3pP.o:(.data+0x0): first defined here
あるいは(そしてより堅牢に)、all-of-C(all-of-posix)ヘッダーを事前にインクルードし、それと衝突している場所をコンパイラーに通知させることができます(それ以外の場合は、たまにしか実行しません)。ビルド時間がいくらか悲観的になります(ただし、POSIXをすべて含めても、C ++ヘッダーを1つでも含めてもそれほど悪くはありません))。
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加