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

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

このコミットは、Go言語のgo/buildパッケージにおけるImport関数の挙動を修正し、空の文字列がインポートパスとして渡された場合にエラーを返すように変更したものです。これにより、不正なインポートパスによる予期せぬ動作を防ぎ、堅牢性を向上させています。

コミット

commit ec9967ff11851facad48bb0c11639e52a77f79b9
Author: Francisco Souza <franciscossouza@gmail.com>
Date:   Thu Sep 13 10:25:35 2012 -0400

    go/build: reject empty strings in Import
    
    Fixes #3889.
    
    R=rsc, adg
    CC=golang-dev
    https://golang.org/cl/6499102

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

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

元コミット内容

go/buildパッケージのImport関数において、空の文字列がインポートパスとして渡された場合に、それを拒否するように変更しました。これにより、Issue #3889で報告された問題が修正されます。

変更の背景

この変更は、Go言語のIssue #3889「go/build: Import("") should return an error」に対応するものです。以前のgo/build.Import関数は、空の文字列をインポートパスとして受け取った場合、エラーを返さずに*Package構造体を返していました。これは、通常、有効なパッケージパスではないため、予期せぬ動作や後続の処理でのエラーを引き起こす可能性がありました。

例えば、ツールがユーザーからの入力を処理する際に、誤って空の文字列がImport関数に渡されると、その後のビルドプロセスが混乱したり、意味のないパッケージ情報が生成されたりする可能性がありました。このコミットは、このような不正な入力に対して早期にエラーを返すことで、ツールの堅牢性と信頼性を向上させることを目的としています。

前提知識の解説

Go言語のgo/buildパッケージ

go/buildパッケージは、Go言語のソースコードを解析し、パッケージの依存関係やビルドに関する情報を提供する標準ライブラリです。go buildコマンドやgo getコマンドなど、Goのツールチェインの多くの部分で内部的に利用されています。

このパッケージの主な機能は以下の通りです。

  • パッケージの解決: 指定されたインポートパスに対応するパッケージのソースディレクトリを特定します。
  • パッケージ情報の取得: パッケージ内のGoソースファイル、C/C++/Assemblyソースファイル、テストファイルなどの情報を収集します。
  • ビルドタグの処理: ビルドタグ(例: // +build linux,amd64)に基づいて、どのファイルをビルドに含めるかを決定します。
  • コンテキストの管理: ビルド環境(GOROOT, GOPATH, OS, Archなど)を管理し、それに基づいてパッケージを解決します。

go/build.Import関数

go/build.Import関数は、go/buildパッケージの中心的な関数の一つです。この関数は、指定されたインポートパスに基づいてGoパッケージを検索し、そのパッケージに関する詳細情報を含む*Package構造体を返します。

関数のシグネチャは以下のようになっています(コミット当時のバージョンに近いもの):

func (ctxt *Context) Import(path string, srcDir string, mode ImportMode) (*Package, error)
  • path: 検索するパッケージのインポートパス(例: "fmt", "github.com/user/repo/pkg")。
  • srcDir: pathが相対パスの場合の基準となるディレクトリ。通常は現在の作業ディレクトリや、インポート元のファイルのディレクトリが指定されます。
  • mode: インポートのモードを指定するフラグ(例: FindOnly, ImportComment, AllowBinaryなど)。FindOnlyはパッケージの検索のみを行い、詳細な解析は行いません。

この関数は、成功した場合は*Packagenilエラーを返し、パッケージが見つからない場合やエラーが発生した場合はnilとエラーを返します。

Go言語のエラーハンドリング

Go言語では、エラーは戻り値として明示的に扱われます。関数がエラーを返す可能性がある場合、通常は最後の戻り値としてerror型の値を返します。呼び出し元は、このerror値がnilであるかどうかをチェックすることで、処理が成功したか失敗したかを判断します。

fmt.Errorf関数は、フォーマットされた文字列から新しいerror値を生成するために使用されます。これは、エラーメッセージに動的な情報を含める場合に便利です。

技術的詳細

このコミットの技術的な変更点は、go/build.Import関数の内部に、インポートパスが空文字列である場合のチェックを追加したことです。

変更前のImport関数は、path引数が空文字列であっても、特にエラーを返さずに処理を進めていました。これにより、*Package構造体のImportPathフィールドが空文字列のままのオブジェクトが生成され、後続の処理で問題を引き起こす可能性がありました。

変更後のコードでは、Import関数の冒頭でpath == ""という条件チェックが追加されています。

if path == "" {
    return p, fmt.Errorf("import %q: invalid import path", path)
}

このチェックにより、pathが空文字列である場合、fmt.Errorfを使用して「import "": invalid import path」というエラーメッセージを含むerrorオブジェクトが生成され、即座にそのエラーが返されるようになりました。この際、p*Package型のポインタ)は、ImportPathが空文字列で初期化された状態のものが返されます。これは、エラーが発生した場合でも、可能な限り部分的な情報を提供しようとするGoの慣習に沿ったものです。

また、この変更には対応するテストケースTestEmptyImportsrc/pkg/go/build/build_test.goに追加されています。このテストは、Import関数に空文字列を渡した場合に、期待通りエラーが返されること、そして返された*PackageオブジェクトのImportPathが空文字列であることを検証しています。

func TestEmptyImport(t *testing.T) {
    p, err := Import("", Default.GOROOT, FindOnly)
    if err == nil {
        t.Fatal(`Import("") returned nil error.`)
    }
    if p == nil {
        t.Fatal(`Import("") returned nil package.`)
    }
    if p.ImportPath != "" {
        t.Fatalf("ImportPath=%q, want %q.", p.ImportPath, "")
    }
}

このテストは以下の点を保証します。

  1. Import("")nilではないエラーを返すこと。
  2. Import("")nilではない*Packageポインタを返すこと(エラー時でも部分的な情報が返されることを確認)。
  3. 返された*PackageImportPathが空文字列であること。

これにより、この変更が正しく機能し、将来のリグレッションを防ぐための自動化された検証が提供されます。

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

src/pkg/go/build/build.go

--- a/src/pkg/go/build/build.go
+++ b/src/pkg/go/build/build.go
@@ -351,6 +351,9 @@ func (ctxt *Context) Import(path string, srcDir string, mode ImportMode) (*Packa
 	p := &Package{
 		ImportPath: path,
 	}
+	if path == "" {
+		return p, fmt.Errorf("import %q: invalid import path", path)
+	}
 
 	var pkga string
 	var pkgerr error

src/pkg/go/build/build_test.go

--- a/src/pkg/go/build/build_test.go
+++ b/src/pkg/go/build/build_test.go
@@ -61,6 +61,19 @@ func TestDotSlashImport(t *testing.T) {\n 	}\n }\n \n+func TestEmptyImport(t *testing.T) {\n+\tp, err := Import(\"\", Default.GOROOT, FindOnly)\n+\tif err == nil {\n+\t\tt.Fatal(`Import(\"\") returned nil error.`)\n+\t}\n+\tif p == nil {\n+\t\tt.Fatal(`Import(\"\") returned nil package.`)\n+\t}\n+\tif p.ImportPath != \"\" {\n+\t\tt.Fatalf(\"ImportPath=%q, want %q.\", p.ImportPath, \"\")\n+\t}\n+}\n+\n func TestLocalDirectory(t *testing.T) {\n 	cwd, err := os.Getwd()\n 	if err != nil {\n```

## コアとなるコードの解説

### `src/pkg/go/build/build.go` の変更

`Import`関数の内部で、`Package`構造体を初期化した直後に、`path`変数が空文字列であるかどうかのチェックが追加されました。
`if path == ""`という条件が真(つまり、インポートパスが空文字列)の場合、`fmt.Errorf`を使ってエラーメッセージ「`import "": invalid import path`」を生成し、そのエラーと初期化された`Package`構造体`p`を返して関数の実行を終了します。これにより、不正なインポートパスが早期に検出され、処理が中断されるようになります。

### `src/pkg/go/build/build_test.go` の変更

`TestEmptyImport`という新しいテスト関数が追加されました。
このテストは、`Import`関数に空文字列`""`をインポートパスとして渡し、`Default.GOROOT`と`FindOnly`モードを使用します。
テストの目的は以下の3点です。
1.  `err == nil`の場合、つまりエラーが返されなかった場合に`t.Fatal`を呼び出してテストを失敗させます。これは、空文字列のインポートパスに対してエラーが返されることを期待しているためです。
2.  `p == nil`の場合、つまり`*Package`ポインタが`nil`であった場合に`t.Fatal`を呼び出してテストを失敗させます。これは、エラー時でも`*Package`構造体自体は(たとえ不完全でも)返されることを期待しているためです。
3.  `p.ImportPath != ""`の場合、つまり返された`*Package`の`ImportPath`フィールドが空文字列でなかった場合に`t.Fatalf`を呼び出してテストを失敗させます。これは、空文字列がインポートパスとして渡された場合、`ImportPath`フィールドも空文字列のままであることを確認するためです。

これらの変更により、`go/build.Import`関数はより堅牢になり、不正な入力に対して明確なエラーを返すようになりました。

## 関連リンク

*   Go Issue #3889: [https://github.com/golang/go/issues/3889](https://github.com/golang/go/issues/3889)
*   Go CL 6499102: [https://golang.org/cl/6499102](https://golang.org/cl/6499102)

## 参考にした情報源リンク

*   Go言語公式ドキュメント: `go/build`パッケージ ([https://pkg.go.dev/go/build](https://pkg.go.dev/go/build))
*   Go言語のエラーハンドリングに関する一般的な情報
*   Go言語のテストに関する一般的な情報
*   GitHubのコミットページ ([https://github.com/golang/go/commit/ec9967ff11851facad48bb0c11639e52a77f79b9](https://github.com/golang/go/commit/ec9967ff11851facad48bb0c11639e52a77f79b9))
*   Go言語のIssueトラッカー ([https://github.com/golang/go/issues](https://github.com/golang/go/issues))
*   Go Code Review ([https://go.dev/doc/contribute#code_reviews](https://go.dev/doc/contribute#code_reviews))
*   Go CL (Change List) ([https://go.dev/doc/contribute#change_lists](https://go.dev/doc/contribute#change_lists))