[インデックス 10057] exp/types: parseBasicType関数のクラッシュ修正
コミット
コミットハッシュ: bb8c4ed22abc40a93a31ef4c3c59841773d75e88
作成者: Russ Cox rsc@golang.org
日付: 2011年10月19日 12:49:01 -0400
メッセージ: exp/types: fix crash in parseBasicType on unknown type
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/bb8c4ed22abc40a93a31ef4c3c59841773d75e88
元コミット内容
diff --git a/src/pkg/exp/types/gcimporter.go b/src/pkg/exp/types/gcimporter.go
index fe90f91080..e744a63a96 100644
--- a/src/pkg/exp/types/gcimporter.go
+++ b/src/pkg/exp/types/gcimporter.go
@@ -289,9 +289,10 @@ func (p *gcParser) parseExportedName() (*ast.Object, string) {
// BasicType = identifier .
//
func (p *gcParser) parseBasicType() Type {
- obj := Universe.Lookup(p.expect(scanner.Ident))
+ id := p.expect(scanner.Ident)
+ obj := Universe.Lookup(id)
if obj == nil || obj.Kind != ast.Typ {
- p.errorf("not a basic type: %s", obj.Name)
+ p.errorf("not a basic type: %s", id)
}
return obj.Type.(Type)
}
変更の背景
このコミットは、Go言語の実験的なパッケージ exp/types
における重要なクラッシュ修正を実装しています。問題は、parseBasicType
関数が未知の型を処理する際に発生していました。
2011年当時、Goは急速に発展しており、型システムの実装が積極的に進められていました。exp/types
パッケージは、後に標準ライブラリの go/types
パッケージに統合される実験的な型システムの実装でした。このパッケージは、Goのコンパイラーツールチェインの重要な部分となる基盤技術を提供していました。
前提知識の解説
exp/typesパッケージの役割
exp/types
パッケージは、Go言語の型システムを実装する実験的なパッケージでした。主な機能は以下の通りです:
- 型チェック: Goのソースコードの型の正確性を検証
- 型推論: 変数や式の型を自動的に推論
- インポート処理: パッケージのインポートと型情報の処理
- 型情報の管理: プログラム全体の型情報を一元管理
gcimporterの役割
gcimporter
は、Go コンパイラ(gc)によって生成されたオブジェクトファイルから型情報を読み込むためのコンポーネントです。主な責務は:
- バイナリ形式の解析: コンパイル済みパッケージのバイナリ形式を解析
- 型情報の復元: バイナリから型情報を復元してメモリ上に展開
- シンボル解決: インポートされたパッケージのシンボル情報を解決
Universeスコープ
Universe
は、Go言語の組み込み型(built-in types)を管理するグローバルスコープです。int
, string
, bool
などの基本型がここに定義されています。
parseBasicType関数
この関数は、基本型の識別子を解析し、対応する型オブジェクトを返す役割を持っています。基本型とは、Go言語で定義されている組み込み型のことです。
技術的詳細
問題の本質
修正前のコードでは、以下の問題が発生していました:
- 潜在的なnilポインタ参照:
Universe.Lookup()
がnil
を返した場合、obj.Name
にアクセスしようとしてクラッシュが発生 - エラーメッセージの不正確性: クラッシュにより、ユーザーに適切なエラーメッセージが表示されない
- デバッグの困難性: クラッシュが発生すると、問題の原因を特定するのが困難
修正の技術的アプローチ
この修正では、以下の技術的改善が実装されました:
- 変数の分離:
p.expect(scanner.Ident)
の結果を一時変数id
に格納 - 安全なエラーハンドリング:
obj
がnil
の場合でも安全にエラーメッセージを生成 - 情報の保持: 元の識別子文字列を保持することで、より正確なエラーメッセージを提供
コアとなるコードの変更箇所
修正前のコード
func (p *gcParser) parseBasicType() Type {
obj := Universe.Lookup(p.expect(scanner.Ident))
if obj == nil || obj.Kind != ast.Typ {
p.errorf("not a basic type: %s", obj.Name) // objがnilの場合クラッシュ
}
return obj.Type.(Type)
}
修正後のコード
func (p *gcParser) parseBasicType() Type {
id := p.expect(scanner.Ident) // 識別子を変数に保存
obj := Universe.Lookup(id) // 分離された検索処理
if obj == nil || obj.Kind != ast.Typ {
p.errorf("not a basic type: %s", id) // 安全なエラーメッセージ
}
return obj.Type.(Type)
}
コアとなるコードの解説
修正の詳細分析
-
id := p.expect(scanner.Ident)
- スキャナーから次の識別子トークンを期待し、それを
id
変数に保存 p.expect()
は、期待されるトークンタイプが見つからない場合にエラーを発生させる- 識別子は基本型の名前(例:
int
,string
,bool
)になる
- スキャナーから次の識別子トークンを期待し、それを
-
obj := Universe.Lookup(id)
- 取得した識別子を使用して、Universeスコープから対応する型オブジェクトを検索
Universe.Lookup()
は、見つからない場合にnil
を返す- この分離により、後続の処理でオリジナルの識別子文字列を使用可能
-
エラーハンドリングの改善
obj == nil
: 指定された識別子が組み込み型として見つからない場合obj.Kind != ast.Typ
: 見つかったオブジェクトが型オブジェクトでない場合p.errorf("not a basic type: %s", id)
: オリジナルの識別子を使用した安全なエラーメッセージ
修正の効果
- クラッシュの防止:
nil
オブジェクトのName
フィールドにアクセスしようとすることによるパニックを防止 - 診断情報の改善: エラーメッセージに実際の識別子名を含めることで、デバッグが容易になる
- コードの堅牢性: 予期しない入力に対してもプログラムが適切に動作する
パフォーマンスへの影響
この修正は、実行時パフォーマンスにほとんど影響を与えません:
- 追加の変数割り当て(
id
)は最小限のオーバーヘッド - 関数呼び出しの順序変更による実行時間への影響は negligible
- メモリ使用量の増加も文字列一つ分のみで無視できる程度
関連リンク
参考にした情報源リンク
- exp/typesパッケージの歴史的背景 - Go言語の週次スナップショット履歴
- gcimporterパッケージドキュメント - 現在のgcimporter実装
- Russ Coxの技術的貢献 - Go言語の発展における重要な貢献者
- Go言語のエラーハンドリング - 適切なエラーハンドリングの重要性