安全でない関数sprintf
と見なされるため、 のような関数の使用をやめてほしい。コードで使用されている場合、またはその他のトリックでコンパイルエラーを発生させるコンパイラの方法はありますか?sprintf
5 に答える
GCC は、この種のことを でサポートしています#pragma GCC poison
。このプラグマの後に識別子のリストを使用すると、プログラム内で識別子を使用するとエラーがスローされます。たとえば、次のプログラムはコンパイルされません。
#include <stdio.h>
#pragma GCC poison fprintf sprintf
int main (void)
{
char foo[100];
sprintf (foo, "bar");
return 0;
}
の前に定義されたマクロpragma
が識別子に展開される場合、その出現は汚染されません。たとえば、このプログラムは次のようにコンパイルされます。
#include <stdio.h>
#define print_to_string sprintf
#pragma GCC poison sprintf
int main (void)
{
char foo[100];
print_to_string (foo, "bar");
return 0;
}
#define sprintf COMPILE_TIME_ERROR
#define COMPILE_TIME_ERROR switch(0){case 0:case 0:;}
int main(void) {
char hi[50];
sprintf(hi,"hi");
return 0;
}
コンパイラの出力は次のようになります。
prog.c: In function ‘main’:
prog.c:6: error: duplicate case value
prog.c:6: error: previously used here
他の人は、コンパイル エラーのトリガーについて言及しています。
残念ながら、エラーを区別したい場合、エラー メッセージはあまり明確ではないことがよくあります。次のように、エラー メッセージを埋め込む名前を持つ未定義のオブジェクトを用意することをお勧めします。
#define sprintf (do_not_use_sprintf_call = 0)
したがって、sprintf
が呼び出されると、gcc
エラー メッセージがより明確になります。
tst.c: In function `main':
tst.c:11: error: `do_not_use_sprintf_call' undeclared (first use in
this function)
tst.c:11: error: (Each undeclared identifier is reported only once
tst.c:11: error: for each function it appears in.)
C11 では、静的アサートを使用して独自のエラー メッセージを表示することもできます。
#define sprintf _Static_assert(0, "do_not_use_sprintf_call")
答えではありませんが、私はあまりにも愚かで、フォーマットされたコードを返信に投稿する方法を知りません。
IMO、@myrkosはこの質問に正しい答えを与えました。
ただし、彼はコンパイル時のエラーについて話します。私はまた、compile time assert
(別名static assert
)に一般化するのが好きです。
それらの用語をグーグルで検索すると、たくさんの提案が表示されます。コンパイラによっては、他のコンパイラよりも心地よいエラーメッセージが表示されるものもあるので、小さなテストプログラムを作成してください。私は個人的に(ymmv)これをGCCで好みます(私がどこからそれを「借りた」のか思い出せないので、元の作者に謝罪します-それはとても昔のことであり、それでも私に役立ちます):
/** A "static assert", which checks a condition at compile time, rather
* than run time. The sooner problems are found, the sooner they can be fixed
* (and with less effort).
*
* Use this one where you don't even want the code to begin running
* if something is wrong. If you don't use this, you need a test case,
* but sometimes tests don't get run, so use this for the sort of thing
* that should never be released to the customer (or even the test department).
*
* Example: ASSERT_AT_COMPILE_TIME(1==2), one_does_not_equal_two);
* gives this error message under GNU on Linux:
* size of array one_does_not_equal_two is negative
*
* Note: this is very useful checking the size of user defined types, like uint64_t
* or for doing things like this:
*
* struct foo {
* int x;
* int y;
* };
* ASSERT_AT_COMPILE_TIME(offsetof(struct foo, y) == 4, y_is_at_offset_4);
*/
#define ASSERT_CAT1(x) ASSERT_CAT ## x
#define ASSERT_CAT0(x) ASSERT_CAT1(x)
#define ASSERT_AT_COMPILE_TIME(expression, message) \
struct ASSERT_CAT0(__LINE__) {char message[2*!!(expression)-1]; }
はい。
LD_PRELOAD をライブラリのリストに設定すると、これらすべてのライブラリが他のライブラリより先にロードされます。上書きする必要がある関数を定義し、ファイルを共有ライブラリにし、この変数をそのライブラリの名前に設定して、実行可能ファイルを実行します。