Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 1320] ファイルの概要

このコミットは、Goコンパイラの一部であるsrc/cmd/6g/obj.cファイルにおけるバグ修正です。具体的には、gentramp関数内で特定の条件が満たされた場合に発生する可能性のあるクラッシュを防ぐためのNULLチェックが追加されています。

コミット

  • コミットハッシュ: a4459c55208e53a010a81f8421b9f10906e291d6
  • Author: Ken Thompson ken@golang.org
  • Date: Wed Dec 10 16:23:29 2008 -0800

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/a4459c55208e53a010a81f8421b9f10906e291d6

元コミット内容

    bug
    
    R=r
    OCL=20940
    CL=20940

変更の背景

このコミットの目的は、Goコンパイラの6g(64ビットシステム向け)における潜在的なバグを修正することです。コミットメッセージは簡潔に「bug」とだけ記されていますが、コードの変更内容から、gentramp関数内で変数dがゼロ(またはNULLポインタ)である場合に、その後の処理で致命的なエラー(fatal関数呼び出し)が発生するのを防ぐことが目的であったと推測されます。このような状況は、コンパイラの実行中に予期せぬクラッシュを引き起こす可能性があり、安定性の向上を目的とした修正と考えられます。

前提知識の解説

Goコンパイラと6g

Go言語は、その初期から複数のアーキテクチャをサポートするために、それぞれのアーキテクチャに対応するコンパイラを持っていました。6gは、Go言語の初期のコンパイラの一つで、AMD64(x86-64)アーキテクチャ、つまり64ビットシステムをターゲットとしていました。現在のGo開発では、go buildコマンドが内部的に適切なコンパイラを選択するため、ユーザーが直接6gのような特定のコンパイラ名を意識することはほとんどありません。しかし、このコミットが作成された2008年当時は、コンパイラの内部構造や特定のアーキテクチャ向けの実装がより直接的に関与していました。

obj.cファイル

obj.cは、Goコンパイラのソースコードの一部であり、通常、オブジェクトファイルの生成に関連するコードを含んでいます。コンパイラは、ソースコードを解析し、中間表現を経て、最終的に機械語の命令を含むオブジェクトファイルを生成します。このファイルは、そのプロセスにおける低レベルな操作、例えばシンボルの解決、コード生成、リンケージに関する処理などを担当している可能性があります。

トランポリン (Trampoline)

プログラミングにおける「トランポリン」とは、あるコードから別のコードへジャンプするための中間的な小さなコード片を指します。これは、直接ジャンプできない状況(例えば、アドレス空間が離れている場合や、特定の呼び出し規約に合わせる必要がある場合)で、間接的な呼び出しを実現するために使用されます。コンパイラにおいては、特定の最適化、ランタイムのフック、または異なるモジュール間の呼び出しを処理するためにトランポリンコードを生成することがあります。gentramp関数は、おそらくこのようなトランポリンコードを生成する役割を担っていたと考えられます。

fatal関数

コンパイラやその他のシステムプログラムにおいて、fatal関数は通常、回復不可能なエラーが発生した場合にプログラムの実行を即座に終了させるために使用されます。これは、プログラムがこれ以上続行できない状態になったことを示し、デバッグ情報やエラーメッセージを出力して終了することが一般的です。

技術的詳細

このコミットの技術的な詳細は、gentramp関数内でのNULLポインタ(またはゼロ値)のチェックに集約されます。

gentramp関数は、トランポリンコードを生成する役割を担っています。この関数内で、dという変数が使用されており、この変数が何らかの理由でゼロ(またはNULLポインタ)になる可能性がありました。元のコードでは、dがゼロである場合に、その後の処理でfatal("gentramp")が呼び出される可能性がありました。これは、dが有効な値でないにもかかわらず、その後の処理が続行され、結果としてコンパイラがクラッシュする原因となり得ました。

追加されたif(d == 0) return;という行は、fatal関数が呼び出される前にdの値をチェックし、もしdがゼロであれば、関数を即座に終了させる(returnする)ようにします。これにより、無効なdの値に基づいてfatalが呼び出されることを防ぎ、コンパイラの安定性を向上させます。この修正は、特定の入力や内部状態においてgentrampが不正なdを受け取る可能性があったことを示唆しており、その不正な状態を安全に処理するための防御的なプログラミングの一例です。

コアとなるコードの変更箇所

--- a/src/cmd/6g/obj.c
+++ b/src/cmd/6g/obj.c
@@ -540,6 +540,9 @@ gentramp(Type *t, Sig *b)
 	fatal("gentramp");
 
 out:
+\tif(d == 0)
+\t\treturn;
+\
 //	print("gentramp %d\\n", d);\
 //	print("\tt    = %lT\\n", t);\
 //	print("\tname = %s\\n", b->name);\

コアとなるコードの解説

変更はsrc/cmd/6g/obj.cファイルのgentramp関数内で行われています。

元のコードでは、out:ラベルの直後にコメントアウトされたprint文があり、その前にfatal("gentramp")という行がありました。このfatal呼び出しは、おそらく特定の条件で到達すべきではないコードパスであったか、またはデバッグ目的で一時的に置かれていたものと推測されます。

追加された以下の3行がこのコミットの核心です。

+\tif(d == 0)
+\t\treturn;
+\

このコードは、out:ラベルの直後、そしてコメントアウトされたprint文の前に挿入されています。

  • if(d == 0): 変数dの値がゼロであるかどうかをチェックします。C言語では、ポインタがNULLであるか、整数値がゼロであるかをこの方法で確認できます。
  • return;: もしdがゼロであれば、現在の関数gentrampの実行を直ちに終了し、呼び出し元に戻ります。

この修正により、dが不正な値(ゼロ)である場合に、その後の処理(もしあれば)や、意図しないfatal呼び出しが実行されることを防ぎます。これは、コンパイラの堅牢性を高め、予期せぬエラーやクラッシュを回避するための重要な防御的プログラミングです。

関連リンク

このコミットはGo言語の非常に初期の段階のものであり、特定の関連する設計ドキュメントや議論が公開されている可能性は低いですが、Go言語のコンパイラ開発に関する一般的な情報は以下のリソースで参照できます。

参考にした情報源リンク