誰もが知っているように、Cは私たちが好きなものを書くことを可能にします。大きな問題が1つあります。標準のライブラリ関数に起因するエラーを処理する責任があるのは私たちだけなので、信頼性の高いコードを作成します。
目標は、信頼性の高いコードを簡単に作成できるようにすることです。
そして問題は、標準ライブラリ関数から生じるエラーについてです。
エラーを隠さないように、標準関数をラップするというアイデアがあります。エラーを無視したい場合は、明示的に行う必要があります。
このコードは私の解決策を示しています:
_void
safe_access
(bool *ok, const char *path, int amode)
{
// reset error
*ok = true;
errno = 0;
int ret = access(path, amode);
// indicate error
if (ret) {
*ok = false;
}
}
_
この関数はunistd.hからのaccess(3)をラップします。次の3つの問題を解決します。
_// this function sets errno
access(...);
// we forget to reset errno and everything seems to be OK
// now, we want to check for errno
// but, unfortunately, we’re prone to check old errno that comes from access()
long a = strtol(...);
if (... && errno) {
}
_
_bool ok;
safe_access(&ok, ...);
// we need something to do with `ok`
_
また、警告を調整して、変数を未使用のままにできないようにすることもできます。
ferror(3)
の後にfread(3)
を使用する必要があります。私の解決策は、それを行うsafe_fread()
を記述することです。リスクはありますか?
セキュリティに誤った印象を与えることは非常に悪い考えです。
今日の同僚が適切なエラーチェックで通話を処理するのに十分な訓練を受けていない場合:
_if (!access ("input.txt", R_OK) || !access ("output.txt", W_OK)) {
// something went wrong, so I have to check fro errno
perror ("Required file not accessible");
}
_
また、ブール値を処理しないだけで、エラーを無視し続けます。
_bool ok;
safe_access (&ok,"input.txt", R_OK);
safe_access (&ok,"output.txt", W_OK);
// oops forgot to check the first one
_
関数のシグネチャをかなり過激な方法で変更するため、よく知られているイディオムがいくつか機能しなくなります。
たとえば、最初のエラーで停止するように_||
_チェーンでいくつかのエラーチェックを組み合わせる例を考えます。しかし、さらに問題の多い通常のループ:
_while (fgets(buffer, BUFLEN, fpin)) {
// do something
}
_
本当に使用しますか?
_safe_fgets (&ok, buffer, BUFLEN, fpin);
while (ok) {
// do something
safe_fgets (&ok, buffer, BUFLEN, fpin); // DRY !!!
}
_
前の例から、safe_xxx()
関数は少なくとも元の関数と同じ戻り値の型を使用する必要があると結論付けることができます。
ただし、式で複数のsafe_xxx()
呼び出しを同じ_&ok
_と組み合わせた場合、およびこれらの呼び出しの順序が不定である場合、未定義の動作に直面する可能性があります。
パラメータの不一致、またはエラーによってNULLポインタを渡すことは言うまでもありません。
最後に、追加のリスクでは、正当な期待を生み出す可能性があることについても触れておきます。たとえば、関数は安全性をアドバタイズするので、次の呼び出しは安全であると期待します。
_char *path=NULL;
// do something
safe_access (&ok, path, R_OK);
_
したがって、最終的には、関数がすべてのチェックを実行すると想定していないと仮定すると、どこでも安全であることを確認することで、賢明さが低下する可能性があります。
ここでは確信が持てませんが、識別可能なリスクの高い呼び出しが別のライブラリ/コンパイルユニットにラップされているため、一定の伝播を無効にする可能性があるため、静的コードアナライザーがいくつかのリスクを見つけられない可能性はありますか?バッファオーバーフロールールに固有
さらに、マニーerrno関連関数はよく知られています。代わりのものを使用することを強制すると、生産性に影響を与える可能性があります。
これはコードレビューとピアプログラミングと呼ばれます:人々がエラーを適切にチェックしていることを確認してください
ここにいくつかの分析があります
利点:
リスク:
bool ok
アプリの状態が複雑になります(path, mode) -> error
他には役に立たない