12

私は非常にマルチスレッド化されたプロジェクトに取り組んでおり、コンパイラに C ライブラリへの再入不可呼び出しの使用にフラグを付ける方法があるかどうか疑問に思っていました (たとえば、strtok_r の strtok intsead)? そうでない場合、コードベースを定期的に検索できるように、再入不可の呼び出しのリストはありますか?

関連する質問は、再入不可の呼び出しの 3d パーティ ライブラリの使用にフラグを付ける方法があるかどうかです。

再入可能性はスレッドセーフを意味すると思いますが、必ずしもその逆ではありません。スレッド化されたプロジェクトで再入不可の呼び出しを使用する正当な理由はありますか?

4

5 に答える 5

5

ソースについては、すべてのソース ファイルに次の行が含まれていると主張できます。

#include <beware.h>

Cヘッダーの後、beware.hヘッダーファイルには次が含まれます。

#define strtok   unsafe_function_call_detected_strtok
#define getenv   unsafe_function_call_detected_getenv

または実際の関数である可能性が低い他の適切な名前のセット。これにより、コンパイル エラーやリンカー エラーが発生します。

ライブラリの場合は、もう少し難しいです。nm各オブジェクト ファイル内のすべての未解決の名前を抽出し、安全でない名前が呼び出されないようにするために使用することを検討できます。

これはコンパイラが行うことではありませんが、ビルド スクリプトに組み込むのは簡単です。次のトランスクリプトを参照してください。

$ cat qq.c
    #include <stdio.h>

    int main (int argc, char *argv[]) {
        printf ("Hello, world.\n");
        return 0;
    }

$ gcc -c -o qq.o qq.c

$ nm qq.o
00000000 b .bss
00000000 d .data
00000000 r .rdata
00000000 t .text
         U ___main
00000000 T _main
         U _puts

その出力の未解決のシンボルをUマーカーで見ることができます (書式設定コマンドなしで定数文字列を指定したため、代わりにgcc使用することを非常にこっそりと決定しました)。putsprintf

于 2011-06-24T01:34:50.980 に答える
3

コードベースを定期的にgrepできるように、再入可能ではない呼び出しのリストはありますか?

GNU libc関数リストを調べて、_rが付いているものを選びました。これがリストです。

asctime、crypt、ctime、drand48、ecvt、encrypt、erand48、fcvt、fgetgrent、fgetpwent、getdate、getgrent、getgrgid、getgrnam、gethostbyaddr、gethostbyname2、gethostbyname、getmntent、getnetgrent、getpwent、getpwnam、getpwuid gmtime、hcreate、hdestroy、hsearch、initstate、jrand48、lcong48、lgamma、lgammaf、lgammal、localtime、lrand48、mrand48、nrand48、ptsname、qecvt、qfcvt、rand、random、readdir64、readdir、seed48、setkey、setstate、srand48、 srandom、strerror、strtok、tmpnam、ttyname

于 2011-06-26T15:41:19.770 に答える
1

あなたの質問の2番目の部分に対処する:

非再入可能呼び出し、パフォーマンスが向上するように実装できます。この場合、これらの呼び出しを 1 つのスレッド (または 1 つのクリティカル セクション内) からのみ行っており、それらがボトルネックであることがわかっている場合、再入不可の呼び出しを選択することは理にかなっています。しかし、そうすることが重要であることを示唆するパフォーマンス測定があった場合にのみ、私はそれを行います...そしてそれを慎重に文書化します..

于 2011-06-24T01:37:44.903 に答える
0

バイナリの場合、LD_PRELOAD好きな C ライブラリ関数をインターセプトし、必要なアクション (中止、エラーをログに記録して続行するなど) を実行するために使用できます。

開発中に、valgrind を使用して同じことを行うこともできます。

いくつかのサンプル コードと参考資料については、「Linux sys 呼び出しをインターセプトするにはどうすればよいですか? 」の回答を参照してください。

于 2011-06-24T04:34:08.063 に答える
0

Cppcheckは、再入不可の標準ライブラリ関数の使用にフラグを立てます。このチェックを有効にするには、移植性の警告を有効にします。

Cppcheck がフラグを立てる関数のリストについては、non_reentrant_functions_listchecknonreentrantfunctions.hを参照してください。

Cppcheck が発行するメッセージの例:

再入不可関数 'strtok' が呼び出されました。スレッドセーフなアプリケーションでは、再入可能な置換関数「strtok_r」を使用することをお勧めします。(移植性: nonreentrantFunctionsstrtok)

于 2014-10-08T18:04:13.223 に答える