ローカル変数のアドレスを返すことについてgccに警告させる方法は?

2012年09月01日に質問されました。  ·  閲覧回数 3.7k回  ·  ソース

md5 picture
2012年09月01日

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

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

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

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

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

回答

Pascal Cuoq picture
2012年09月01日
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
... 

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

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()を分析し、実際に渡された値を使用します。 また、関数caller()h()を呼び出した後に来るコードを、 h()が実際に返すことができる値で分析します。 これは、ClangまたはGCCが通常行うコンテキストに依存しない分析よりもコストがかかりますが、より正確です。

teppic picture
2012年09月01日
1

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

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

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

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

この問題を検出するもう1つのユーティリティは、スプリント(http://splint.org)です。