到達不能コード到達不能コード(とうたつふのうコード、英: unreachable code)は、コンピュータ・プログラムの一部として存在するが、決して実行されないコードのことである。たとえば機械語プログラムであれば、プログラムカウンタ(インストラクションポインタ)が、そのアドレスに到達することは決してない(到達不能である)。 到達不能コードは以下のような理由から好ましくない。
到達不能コードはデッドコード(英: dead code)の一種である(デッドコード削除も参照)。デッドコードには、「冗長コード」なども含まれる。冗長コードは例えば、同じアドレスに同じ内容を繰り返し書き込む、あるいは内容が変化する可能性が無いのに繰り返し読み出す、などといったコードで[注釈 1]、実行しても意味のある影響が無いコードである。他に、宣言されているが実際には使われない変数などの宣言を「冗長宣言」などと呼ぶこともある。 到達不能コードの検出→詳細は「デッドコード削除」を参照
静的コード解析の一種としては、変数の値やその他の実行時の条件がどうであっても決して実行されないコードを、単純なものでは制御構造の分析によって、より高度には抽象解釈などにより[注釈 2]検出する。一部のプログラミング言語(Javaなど)では、ある種の[注釈 3]到達不能コードは言語の仕様上許容されない。デッドコードの削除について詳しくはデッドコード削除の記事を参照のこと。 しかし、静的に決定が可能なパターンの到達不能コードの検出は、そういったコードを意図的に書くことは無いといった意味では、最適化よりも、バグ(の可能性)を警告する、といった目的のためのほうが有用かもしれない。 また、実際のところ、静的解析よりも、実行時の動的な最適化(例えばコマンドライン引数に対応して、動的コード生成を行うプログラムなどがある)の際のほうが、if文の条件式などが恒真式になったりして、到達不能コードが現れやすいかもしれない。 コンパイラによる高度な最適化などの結果によっては、例えば共通式削除などで、ソースコード中には複数あらわれる表現であるのに、オブジェクトコード中で相当するのは一箇所だけ、といったような場合も、一種のデッドコードのようなものとして、デバッガなどからは見える場合もある。 到達不能コードが生まれる原因以下では、到達不能コードが生じる原因をいくつか解説する。 ソフトウェア開発の際、プログラマは一時的にコードが実行されないようにすることがある(すなわち、明示的に実行されないように書き換える)。例えば、次のようなC言語のコードがある。 while (condition)
{
foo();
bar();
}
ここで、一時的に while (condition)
{
foo();
continue;
bar();
}
この例では、 他の到達不能コードが生じる原因として、条件判断が冗長化している場合や、デバッグ用コードを削除せずに残してしまう場合がある。 関数やサブルーチンは、どこからも呼び出されない場合はデッドコードになるし、到達不能コードからのみ呼び出されている関数もデッドコードになる。 到達不能コードの存在は、プログラムの修正時の論理的誤りや、プログラムの前提や環境が大幅に変更されたことを示す場合もある。到達不能コードの存在を許容する言語もあれば、許容しない言語もあるが、前者であっても優れたコンパイラはデッドコードの存在を通知し、保守者がその意味を考えられるようにする[注釈 4]。なお、到達不能コードを許容する言語であっても、ほとんどのコンパイラは、決して実行されることのないコードは最適化の際に除去してしまうため、最終的にリリース用に生成される機械語には痕跡も残らない。 到達不能性の検証任意のコードが到達不能コードかどうかを判断することは停止性問題を解くことと等価である。すなわち、あらゆる到達不能コードを正しく把握することは不可能である。 実際には分析手法は精巧化しており、到達不能コードを検出する量は大幅に改善されている。例えば以下のコードで、定数畳み込みや単純なフロー解析では、 int n = 2 + 1; // 右辺は 3 に定数畳み込みされる。つまりコンパイル時定数となる。
// 3 != 4 なので常に実行されない。
if (n == 4)
{
xyz;
}
しかし、以下のコードで double x = sqrt(2.0);
if (x > 2.0)
{
xyz;
}
到達不能性とプロファイリング場合によっては、静的コード解析による通常の手法と同時に、プロファイラを使って複雑なケースを検出できる場合もある。プロファイラはコードの到達不能性を「証明」できるわけではないが、到達不能コードを見つけ出すヒューリスティクスとしては優れている。疑わしい部分が見つかったら、もっと強力な分析ツールを使ったり、人間が目と手で調査して、そのコードが本当に到達不能かどうかを判断する。 脆弱性と到達不能性以下の例は、AppleによるTLS/SSLの実装上のバグであり、CVE番号として CVE-2014-1266 が与えられているほか、"goto fail bug" とも呼ばれている[3][4]。実際のコードは以下の通りである[5]。 static OSStatus
SSLVerifySignedServerKeyExchange(SSLContext *ctx, bool isRsa, SSLBuffer signedParams,
uint8_t *signature, UInt16 signatureLen)
{
OSStatus err;
...
if ((err = SSLHashSHA1.update(&hashCtx, &serverRandom)) != 0)
goto fail;
if ((err = SSLHashSHA1.update(&hashCtx, &signedParams)) != 0)
goto fail;
goto fail;
if ((err = SSLHashSHA1.final(&hashCtx, &hashOut)) != 0)
goto fail;
...
fail:
SSLFreeBuffer(&signedHashes);
SSLFreeBuffer(&hashCtx);
return err;
}
脚注注釈
出典
関連項目 |
Portal di Ensiklopedia Dunia