[インデックス 12190] ファイルの概要
コミット
commit 9984a5bca403ec14340a05c6fd57fcbefd96f4df
Author: Russ Cox <rsc@golang.org>
Date: Thu Feb 23 22:45:55 2012 -0500
cmd/cc: grow some global arrays
Avoids global array buffer overflows if they are
indexed using some of the values between NTYPE
and NALLTYPE. It is entirely likely that not all of these
are necessary, but this is the C compiler and not worth
worrying much about. This change takes up only a
few more bytes of memory and makes the behavior
deterministic.
Fixes #3078.
R=golang-dev, bradfitz
CC=golang-dev
https://golang.org/cl/5693052
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/9984a5bca403ec14340a05c6fd57fcbefd96f4df
元コミット内容
cmd/cc: grow some global arrays
Avoids global array buffer overflows if they are
indexed using some of the values between NTYPE
and NALLTYPE. It is entirely likely that not all of these
are necessary, but this is the C compiler and not worth
worrying much about. This change takes up only a
few more bytes of memory and makes the behavior
deterministic.
Fixes #3078.
R=golang-dev, bradfitz
CC=golang-dev
https://golang.org/cl/5693052
変更の背景
このコミットは、Go言語の初期のCコンパイラ (cmd/cc
) におけるグローバル配列のバッファオーバーフローを防ぐことを目的としています。具体的には、NTYPE
と NALLTYPE
の間の値が配列のインデックスとして使用された場合に発生する可能性のある問題を解決します。
コミットメッセージには「Fixes #3078」とありますが、現在のGoプロジェクトのGitHub Issuesでこの番号を検索しても直接関連する情報は見つかりませんでした。これは、Goの初期開発段階で使われていた別の課題追跡システム(例えば、Google CodeのIssue Trackerなど)の番号である可能性が高いです。
コンパイラのような重要なツールにおいて、バッファオーバーフローは予期せぬクラッシュ、誤ったコード生成、さらにはセキュリティ上の脆弱性につながる可能性があるため、このような問題の修正はシステムの安定性と信頼性を確保する上で不可欠です。コミットメッセージにある「makes the behavior deterministic(動作を決定論的にする)」という記述は、オーバーフローによって引き起こされる可能性のある非決定的な挙動(例えば、メモリ上のランダムな場所が上書きされることによる予測不能な結果)を排除することの重要性を示しています。
前提知識の解説
- Cコンパイラ (
cmd/cc
): Go言語は初期段階で、C言語で書かれたツールチェイン(コンパイラ、アセンブラ、リンカなど)を使用していました。cmd/cc
はそのCコンパイラの一部であり、Goのソースコードを機械語に変換する過程で重要な役割を担っていました。Go言語自体が成熟するにつれて、これらのCベースのツールはGo言語で書かれたツール(gc
など)に置き換えられていきました。 - グローバル配列 (Global Arrays): プログラムの実行中、常にメモリ上に存在し、どの関数からもアクセス可能な配列です。C言語では、グローバル変数は通常、プログラムの開始時に初期化され、プログラムの終了時に解放されます。
- バッファオーバーフロー (Buffer Overflow): プログラムが、割り当てられたバッファ(配列など)の境界を超えてデータを書き込もうとしたときに発生する脆弱性またはエラーです。これにより、隣接するメモリ領域が上書きされ、プログラムのクラッシュ、予期せぬ動作、または悪意のあるコードの実行につながる可能性があります。
NTYPE
とNALLTYPE
: これらはC言語のプリプロセッサマクロ(#define
で定義される定数)であると推測されます。コンパイラ内部で型を表すための列挙型や定数に関連している可能性が高いです。NTYPE
: おそらく、基本的な型(整数型、浮動小数点型など)の数を表す定数。NALLTYPE
:NTYPE
よりも多くの型、例えば、構造体、共用体、関数ポインタなど、より複雑な型を含む、すべての可能な型の数を表す定数。 コンパイラが内部で型情報を管理するために配列を使用している場合、これらの定数は配列のサイズを決定するために使われます。もし、NTYPE
のサイズで宣言された配列にNALLTYPE
の範囲のインデックスでアクセスしようとすると、バッファオーバーフローが発生します。
- 決定論的挙動 (Deterministic Behavior): プログラムが同じ入力に対して常に同じ出力を生成し、同じ状態遷移をたどることを指します。コンパイラのようなツールでは、入力ソースコードが同じであれば、常に同じ実行可能ファイルを生成することが期待されます。バッファオーバーフローのような非決定的な問題は、この決定論的挙動を損なう可能性があります。
技術的詳細
このコミットの技術的な核心は、Cコンパイラ (cmd/cc
) 内で宣言されているいくつかのグローバル配列のサイズを拡張することにあります。具体的には、配列のサイズを定義するために使用されていた NTYPE
マクロを、より大きな値を持つ NALLTYPES
マクロに置き換えています。
コンパイラは、プログラムの型システムを内部で表現するために、様々なデータ構造を使用します。これらのデータ構造の中には、型の種類や特性に基づいてインデックス付けされる配列が含まれることがあります。もし、これらの配列が、コンパイラが処理する必要があるすべての型を格納するのに十分な大きさでない場合、特に NTYPE
と NALLTYPE
の間の「追加の型」がインデックスとして使用された場合に、バッファオーバーフローが発生する可能性があります。
この変更は、配列のサイズを NALLTYPES
に増やすことで、コンパイラが扱う可能性のあるすべての型に対応できるようにします。これにより、インデックスが配列の境界を超えることがなくなり、バッファオーバーフローが防止されます。
コミットメッセージには「It is entirely likely that not all of these are necessary, but this is the C compiler and not worth worrying much about. This change takes up only a few more bytes of memory and makes the behavior deterministic.」とあります。これは、以下の点を意味しています。
- 過剰な割り当ての可能性:
NALLTYPES
が実際に必要とされる最大インデックスよりも大きい可能性があることを示唆しています。つまり、一部の配列は必要以上に大きくされているかもしれません。 - Cコンパイラの文脈: Cコンパイラのような低レベルでパフォーマンスが重要なソフトウェアでは、メモリ使用量を厳密に最適化することが一般的です。しかし、このケースでは、わずかなメモリ増加(「few more bytes of memory」)は、バッファオーバーフローという深刻な問題を解決し、コンパイラの動作を決定論的にするというメリットに比べて取るに足らないと判断されています。
- 決定論的挙動の確保: バッファオーバーフローは、メモリ上の予期せぬ領域を破壊し、プログラムの動作を非決定的にする可能性があります。配列サイズを適切に拡張することで、この非決定性を排除し、コンパイラが常に予測可能な結果を生成するようにします。これは、ソフトウェアの品質と信頼性にとって非常に重要です。
この修正は、コンパイラの堅牢性を高め、将来的な潜在的なバグやクラッシュを防ぐための予防的な措置であると言えます。
コアとなるコードの変更箇所
このコミットでは、以下の4つのファイルが変更されています。
src/cmd/cc/cc.h
src/cmd/cc/com64.c
src/cmd/cc/funct.c
src/cmd/cc/sub.c
これらのファイルでは、主にグローバル配列の宣言において、配列のサイズ指定が NTYPE
から NALLTYPES
に変更されています。
変更の概要:
cc.h
: 型定義に関連するヘッダファイルで、Type* types[]
とType* fntypes[]
のサイズが変更されています。com64.c
: コンパイラのバックエンドの一部で、char etconv[]
のサイズが変更されています。funct.c
: 関数処理に関連するファイルで、Gtab gtabinit[]
のサイズが変更されています。sub.c
: サブルーチンやユーティリティ関数を含むファイルで、多数の型関連の配列(typei
,typeu
,typesuv
,typeilp
,typechl
,typechlv
,typechlvp
,typechlp
,typechlpfd
,typec
,typeh
,typeil
,typev
,typefd
,typeaf
,typesu
,tasign
,tasadd
,tcast
,tadd
,tsub
,tmul
,tand
,trel
など)のサイズが変更されています。
コアとなるコードの解説
変更は非常にシンプルで、配列の宣言におけるサイズ指定のマクロを NTYPE
から NALLTYPES
に一括で置き換えるものです。
src/cmd/cc/cc.h
の変更例:
--- a/src/cmd/cc/cc.h
+++ b/src/cmd/cc/cc.h
@@ -517,8 +517,8 @@ EXTERN int thechar;
EXTERN char* thestring;
EXTERN Type* thisfn;
EXTERN int32 thunk;
-EXTERN Type* types[NTYPE];
-EXTERN Type* fntypes[NTYPE];
+EXTERN Type* types[NALLTYPES];
+EXTERN Type* fntypes[NALLTYPES];
EXTERN Node* initlist;
EXTERN Term term[NTERM];
EXTERN int nterm;
ここでは、types
と fntypes
という Type*
型の配列のサイズが NTYPE
から NALLTYPES
に変更されています。これらの配列は、コンパイラが内部で型情報を管理するために使用されると考えられます。
src/cmd/cc/com64.c
の変更例:
--- a/src/cmd/cc/com64.c
+++ b/src/cmd/cc/com64.c
@@ -96,7 +96,7 @@ Node* nodmmv;
Node* nodvasop;
-char etconv[NTYPE]; /* for _vasop */
+char etconv[NALLTYPES]; /* for _vasop */
Init initetconv[] =
{
TCHAR, 1, 0,
etconv
という char
型の配列のサイズが変更されています。これは、型変換に関連するテーブルである可能性があります。
src/cmd/cc/funct.c
の変更例:
--- a/src/cmd/cc/funct.c
+++ b/src/cmd/cc/funct.c
@@ -46,7 +46,7 @@ struct Gtab
};
Ftab ftabinit[OEND];
-Gtab gtabinit[NTYPE];
+Gtab gtabinit[NALLTYPES];
int
isfunct(Node *n)
@@ -350,7 +350,7 @@ bad:
diag(Z, "dclfunct bad %T %s\n", t, s->name);
}
-Gtab gtabinit[NTYPE] =
+Gtab gtabinit[NALLTYPES] =
{
TCHAR, "c",
TUCHAR, "uc",
gtabinit
という Gtab
型の配列のサイズが変更されています。これは、関数の型情報や関連するデータ構造を格納するために使用されると考えられます。
src/cmd/cc/sub.c
の変更例:
sub.c
では、typei
, typeu
, typesuv
, typeilp
, typechl
, typechlv
, typechlvp
, typechlp
, typechlpfd
, typec
, typeh
, typeil
, typev
, typefd
, typeaf
, typesu
, tasign
, tasadd
, tcast
, tadd
, tsub
, tmul
, tand
, trel
といった多数の uchar
または int32
型の配列のサイズが NTYPE
から NALLTYPES
に変更されています。これらの配列は、コンパイラが型システム内で様々な型関連のプロパティ、変換ルール、または操作を管理するために使用するルックアップテーブルやフラグであると推測されます。
例えば、typei
は整数型に関連する情報、typefd
は浮動小数点型に関連する情報、typesu
は構造体や共用体に関連する情報を格納している可能性があります。これらの配列のサイズを増やすことで、コンパイラが処理できる型の範囲が広がり、既存の型定義の拡張や新しい型の追加があった場合でも、バッファオーバーフローのリスクを回避できます。
全体として、この変更は、コンパイラが内部で型情報を扱う際の堅牢性を高め、潜在的なメモリ関連のバグを防ぐための重要な修正です。
関連リンク
- GitHubコミットページ: https://github.com/golang/go/commit/9984a5bca403ec14340a05c6fd57fcbefd96f4df
- Go CL (Change List): https://golang.org/cl/5693052
参考にした情報源リンク
- コミットメッセージ自体
- C言語におけるグローバル配列とバッファオーバーフローに関する一般的な知識
- コンパイラの設計と実装に関する一般的な知識
- Go言語の初期のツールチェインに関する歴史的背景