19

コンパイラは、コードに到達できない場合に警告するスイッチを提供するのが一般的です。また、到達不能コードのアサーションを提供する一部のライブラリのマクロも確認しました。

プラグマやビルトインなど、GCC(またはその他のコンパイラ)に渡すことができるヒントはありますか?到達できないと予想される行に実際に到達できると判断された場合、コンパイル中に警告またはエラーが発生します?

次に例を示します。

    if (!conf->devpath) {
        conf->devpath = arg;
        return 0;
    } // pass other opts into fuse
    else {
        return 1;
    }
    UNREACHABLE_LINE();

これの価値は、予想される到達不能線を超える条件が変化した後、その線が実際に到達可能であることを検出することです。

4

4 に答える 4

21

gcc 4.5は__builtin_unreachable()コンパイラーをインラインでサポートしており、これを組み合わせることで-Wunreachable-code希望どおりの結果が得られる可能性がありますが、誤った警告が発生する可能性があります。

于 2010-08-01T11:37:24.763 に答える
6

gcc 4.4.0 WindowsクロスコンパイラからPowerPCへの-O2または-O3でのコンパイルでは、次のように機能します。

#define unreachable asm("unreachable\n")

アセンブラは、到達不能であると判断したためにコンパイラが最適化しない場合、不明な操作で失敗します。

はい、それはおそらく「さまざまな最適化オプションの下では非常に予測不可能」であり、最終的にコンパイラを更新したときに壊れてしまう可能性がありますが、今のところ何もないよりはましです。

于 2018-01-22T16:27:58.587 に答える
6

__builtin_unreachable()GCC 7.3.0で確認できる限り、コンパイル時の警告は生成されません。

また、ドキュメントでそうなることを示唆するものを見つけることもできません。

たとえば、次の例は警告なしでコンパイルされます。

#include <stdio.h>

int main(void) {
    __builtin_unreachable();
    puts("hello")
    return 0;
}

と:

gcc -ggdb3 -O0 -std=c99 -Wall -Wextra -Wunreachable-code main.c

私が思うに、それ行う唯一のことは、コードの特定の行に到達しないという事実に基づいてコンパイラが特定の最適化を実行できるようにし、プログラミングエラーが発生した場合に未定義の動作を与えることです。

たとえば、上記の例を実行すると、正常に終了したように見えますがhello、期待どおりに出力されません。次に、アセンブリ分析は、通常の外観の出口が単なるUBの一致であったことを示しています。

-fsanitize=unreachableGCCへのフラグ__builtin_unreachable();は、実行時に次のように失敗するアサーションに変換します。

<stdin>:1:17: runtime error: execution reached a __builtin_unreachable() call

ただし、そのフラグはUbuntu 16.04では壊れています。ld:認識されないオプション'--push-state--no-as-needed'

実行可能ファイルは__builtin_unreachable()どうなりますか?

コードがある場合とない場合の両方を逆アセンブルすると、次のようになります__builtin_unreachable

objdump -S a.out

それがないものが呼び出すことがわかりますputs

000000000000063a <main>:
#include <stdio.h>

int main(void) {
 63a:   55                      push   %rbp
 63b:   48 89 e5                mov    %rsp,%rbp
    puts("hello");
 63e:   48 8d 3d 9f 00 00 00    lea    0x9f(%rip),%rdi        # 6e4 <_IO_stdin_used+0x4>
 645:   e8 c6 fe ff ff          callq  510 <puts@plt>
    return 0;
 64a:   b8 00 00 00 00          mov    $0x0,%eax
}
 64f:   5d                      pop    %rbp
 650:   c3                      retq
 651:   66 2e 0f 1f 84 00 00    nopw   %cs:0x0(%rax,%rax,1)
 658:   00 00 00
 65b:   0f 1f 44 00 00          nopl   0x0(%rax,%rax,1)

一方、ないものは次のことだけを行います。

int main(void) {
 5fa:   55                      push   %rbp
 5fb:   48 89 e5                mov    %rsp,%rbp
 5fe:   66 90                   xchg   %ax,%ax

戻ってこないので、爆発しただけではないのは、未定義の動作の偶然だと思います。

一部のコードが到達不能かどうかをGCCが判断できないのはなぜですか?

私は次の答えを集めます:

  • 到達不能コードを自動的に決定することは、何らかの理由でGCCにとって難しすぎるため、何年もの間-Wunreachable-code何もしません。gccは到達不能コードについて警告しません。

  • ユーザーは到達不能を意味するインラインアセンブリを使用できますが、GCCはそれを判別できません。これはGCCマニュアルに記載されています:

    そのようなケースの1つは、決して終了しないasmステートメントの直後、または制御を他の場所に移して決して戻らないasmステートメントの直後です。この例では、__ builtin_unreachableがないと、GCCは制御が非void関数の終わりに到達したという警告を発行します。また、asmの後に戻るコードも生成します。

    int f (int c, int v)
    {
      if (c)
        {
          return v;
        }
      else
        {
          asm("jmp error_handler");
          __builtin_unreachable ();
        }
    }
    

GCC 7.3.0、Ubuntu18.04でテスト済み。

于 2018-10-09T13:57:41.543 に答える
2

コンパイラに必要な警告がない場合は、静的アナライザで補完できます。私が話している種類のアナライザーは、独自の注釈言語を持っているか、Cassertを認識し、実行の特定のポイントで真である必要があるプロパティのヒントにこれらを使用します。到達不能なステートメントに特定のアノテーションがない場合は、おそらくを使用できますassert (false);

私は個人的にはそれらに精通していませんが、KlokworkとCodeSonarは2つの有名なアナライザーです。ゴアナは3番目です。

于 2010-08-01T10:13:10.327 に答える