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

[インデックス 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言語の型システムを実装する実験的なパッケージでした。主な機能は以下の通りです:

  1. 型チェック: Goのソースコードの型の正確性を検証
  2. 型推論: 変数や式の型を自動的に推論
  3. インポート処理: パッケージのインポートと型情報の処理
  4. 型情報の管理: プログラム全体の型情報を一元管理

gcimporterの役割

gcimporter は、Go コンパイラ(gc)によって生成されたオブジェクトファイルから型情報を読み込むためのコンポーネントです。主な責務は:

  1. バイナリ形式の解析: コンパイル済みパッケージのバイナリ形式を解析
  2. 型情報の復元: バイナリから型情報を復元してメモリ上に展開
  3. シンボル解決: インポートされたパッケージのシンボル情報を解決

Universeスコープ

Universe は、Go言語の組み込み型(built-in types)を管理するグローバルスコープです。int, string, bool などの基本型がここに定義されています。

parseBasicType関数

この関数は、基本型の識別子を解析し、対応する型オブジェクトを返す役割を持っています。基本型とは、Go言語で定義されている組み込み型のことです。

技術的詳細

問題の本質

修正前のコードでは、以下の問題が発生していました:

  1. 潜在的なnilポインタ参照: Universe.Lookup()nil を返した場合、obj.Name にアクセスしようとしてクラッシュが発生
  2. エラーメッセージの不正確性: クラッシュにより、ユーザーに適切なエラーメッセージが表示されない
  3. デバッグの困難性: クラッシュが発生すると、問題の原因を特定するのが困難

修正の技術的アプローチ

この修正では、以下の技術的改善が実装されました:

  1. 変数の分離: p.expect(scanner.Ident) の結果を一時変数 id に格納
  2. 安全なエラーハンドリング: objnil の場合でも安全にエラーメッセージを生成
  3. 情報の保持: 元の識別子文字列を保持することで、より正確なエラーメッセージを提供

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

修正前のコード

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)
}

コアとなるコードの解説

修正の詳細分析

  1. id := p.expect(scanner.Ident)

    • スキャナーから次の識別子トークンを期待し、それを id 変数に保存
    • p.expect() は、期待されるトークンタイプが見つからない場合にエラーを発生させる
    • 識別子は基本型の名前(例:int, string, bool)になる
  2. obj := Universe.Lookup(id)

    • 取得した識別子を使用して、Universeスコープから対応する型オブジェクトを検索
    • Universe.Lookup() は、見つからない場合に nil を返す
    • この分離により、後続の処理でオリジナルの識別子文字列を使用可能
  3. エラーハンドリングの改善

    • obj == nil: 指定された識別子が組み込み型として見つからない場合
    • obj.Kind != ast.Typ: 見つかったオブジェクトが型オブジェクトでない場合
    • p.errorf("not a basic type: %s", id): オリジナルの識別子を使用した安全なエラーメッセージ

修正の効果

  1. クラッシュの防止: nil オブジェクトの Name フィールドにアクセスしようとすることによるパニックを防止
  2. 診断情報の改善: エラーメッセージに実際の識別子名を含めることで、デバッグが容易になる
  3. コードの堅牢性: 予期しない入力に対してもプログラムが適切に動作する

パフォーマンスへの影響

この修正は、実行時パフォーマンスにほとんど影響を与えません:

  • 追加の変数割り当て(id)は最小限のオーバーヘッド
  • 関数呼び出しの順序変更による実行時間への影響は negligible
  • メモリ使用量の増加も文字列一つ分のみで無視できる程度

関連リンク

参考にした情報源リンク