12

4.4.5ではgcc、次のコードで警告が表示されます。

char *f(void)
{
    char c;
    return &c;
}

しかし、一時ポインターを使用すると、警告は表示されなくなります (動作が間違っていても)。

char *f(void)
{
    char c;
    char *p = &c;
    return p;
}

Cではポインタ解析が難しいと聞きましたが、そのgccようなコードについて警告できますか?

4

2 に答える 2

9

コンパイラー、およびほとんどの静的アナライザーは、プログラムが行う可能性のあるすべての間違いを警告しようとはしません。これは、あまりにも多くの誤検知 (ソース コード内の実際の問題に対応しない警告) を伴うためです。

MacmadeはコメントでClangを推奨しています。Clang は、誤検知を最小限に抑えることで、ほとんどの開発者にとって有用であることを依然として目指していることに注意してください。これは、偽陰性があること、つまり、実際の問題がいくつか見逃されていることを意味します (問題があるかどうかわからない場合は、偽陽性で開発者の時間を無駄にする危険を冒すのではなく、黙っていることができます)。


f()プログラムの機能に本当に問題があるかどうかについては議論の余地があることに注意してください。以下の関数h()は明らかに問題ありませんが、呼び出し元のコードはp返された後に使用してはなりません。

char *p;

void h(void)
{
    char c;
    p = &c;
}

私がお勧めできるもう 1 つの静的アナライザーは、Frama-C の値分析です (私は開発者の 1 人です)。これは、制御された条件で使用された場合、エラーの一部のファミリ (ダングリング ポインターを含む) に対して、偽陰性を残しません。

char *f(void)
{
    char c;
    return &c;
}

char *g(void)
{
    char c;
    char *p = &c;
    return p;
}

$ frama-c -val -lib-entry -main g r.c
...
r.c:11:[value] warning: locals {c} escaping the scope of g through \result
...
$ frama-c -val -lib-entry -main f r.c
...
r.c:4:[value] warning: locals {c} escaping the scope of f through \result
... 

上記は単なる情報メッセージであり、関数が必ずしも間違っていることを意味するものではありません。私の機能にも1つありh()ます:

h.c:7:[value] warning: locals {c} escaping the scope of h through p

Frama-C の出力の「assert」という単語によって特徴付けられる実際のエラーは、関数が呼び出しh()てから次を使用した場合pです。

void caller(void)
{
  char d;
  h();
  d = *p;
}

$ frama-c -val -lib-entry -main caller h.c
...
h.c:7:[value] warning: locals {c} escaping the scope of h through p
...
h.c:13:[kernel] warning: accessing left-value p that contains escaping addresses; assert(Ook)
h.c:13:[kernel] warning: completely undefined value in {{ p -> {0} }} (size:<32>).

Frama-C の価値分析は状況依存型と呼ばれます。h()実際に渡された値を使用して、呼び出しごとに関数を分析します。また、h()in 関数の呼び出しの後に来るコードをcaller()、 によって実際に返される値で分析しますh()。これは、Clang や GCC が通常行うコンテキストに依存しない分析よりもコストがかかりますが、より正確です。

于 2012-09-01T15:18:48.443 に答える
1

この最初の例では、gcc は、もはや存在しない自動変数のアドレスを返していることを明確に確認できます。2 番目の場合、p は有効なもの (外部文字変数など) を簡単に指すことができるため、コンパイラはプログラムのロジックに従う必要があります。

gcc はここでは文句を言いませんが、次のようなポインタの使用で警告します:

char *f(const char *x)
{
  char *y = x;
  ...
}

繰り返しになりますが、この定義で「const」修飾子を削除していることは間違いありません。

この問題を検出する別のユーティリティは splint (http://splint.org) です。

于 2012-09-01T15:01:24.040 に答える