[インデックス 17841] ファイルの概要
このコミットは、Go言語のnet
パッケージにおける、ホストファイルの読み込みに関するバグ修正です。具体的には、末尾に改行がない単一行のホストファイルを正しく処理できるようにするための変更が含まれています。
コミット
commit 5644774ea5c954a08c1e068be9771429a232ca7c
Author: Josh Bleecher Snyder <josharian@gmail.com>
Date: Mon Oct 28 19:31:25 2013 -0400
net: handle single-line non-\n-terminated files correctly in readLine
Fixes #6646.
R=rsc, bradfitz
CC=golang-dev
https://golang.org/cl/15960047
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/5644774ea5c954a08c1e068be9771429a232ca7c
元コミット内容
このコミットは、net
パッケージのreadLine
関数が、末尾に改行文字(\n
)がない単一行のファイルを正しく処理できない問題を修正します。この問題は、特に/etc/hosts
のような設定ファイルを読み込む際に発生する可能性があり、Goアプリケーションがホスト名を解決する際に予期せぬ動作を引き起こす可能性がありました。
変更の背景
Go言語のnet
パッケージは、ネットワーク関連の操作、特にDNSルックアップやホスト名の解決を担当しています。多くのUnix系システムでは、/etc/hosts
ファイルがローカルのホスト名解決に使用されます。このファイルは通常、各エントリが改行で区切られた行として記述されます。しかし、一部の環境や手動での編集によって、ファイルが単一行で構成され、かつその行の末尾に改行文字がない場合があります。
従来のreadLine
関数は、行の終端を改行文字またはファイルの終端(EOF)で判断していました。しかし、末尾に改行がない単一行の場合、io.EOF
ではなくio.ErrUnexpectedEOF
が返されることがあり、このケースが適切に処理されていませんでした。その結果、このような形式のホストファイルが正しくパースされず、ホスト名の解決に失敗する可能性がありました。
この問題は、GoのIssue #6646として報告されており、本コミットはその修正を目的としています。
前提知識の解説
/etc/hosts
ファイル: Unix系システムで使用される、IPアドレスとホスト名のマッピングを定義するテキストファイルです。DNSが利用できない場合や、特定のホスト名をローカルでオーバーライドする場合に参照されます。io.EOF
: Go言語のio
パッケージで定義されているエラーで、入力ストリームの終端に達したことを示します。通常、ファイルの最後まで読み込んだ場合に返されます。io.ErrUnexpectedEOF
: Go言語のio
パッケージで定義されているエラーで、予期せぬファイルの終端に達したことを示します。例えば、期待されるデータが読み込まれる前にファイルの終端に達した場合などに発生します。今回のケースでは、改行文字を期待しているにもかかわらず、ファイルの終端に達してしまった場合に発生します。bufio.Reader
: Go言語のbufio
パッケージで提供される、バッファリングされたI/O操作を行うためのリーダーです。効率的なファイル読み込みを可能にします。readLine
関数: 一般的に、ファイルやストリームから一行ずつデータを読み込むための関数です。改行文字を区切りとして行を認識します。
技術的詳細
このコミットの主要な変更点は、src/pkg/net/parse.go
内のfile
構造体のreadLine
メソッドにあります。このメソッドは、ホストファイルのようなテキストファイルを読み込み、行ごとに処理するために使用されます。
修正前は、readLine
メソッド内でio.EOF
のみをファイルの終端として扱っていました。しかし、末尾に改行がない単一行のファイルの場合、bufio.Reader
のReadSlice
メソッドはio.ErrUnexpectedEOF
を返すことがあります。これは、ReadSlice
が改行文字を探している途中でファイルの終端に達したことを意味します。
このコミットでは、io.EOF
だけでなくio.ErrUnexpectedEOF
もファイルの終端を示すものとして扱うように変更されました。これにより、readLine
は末尾に改行がない単一行のファイルでも、その行を正しく読み込み、ファイルの終端に達したと認識できるようになります。
また、この修正を検証するために、src/pkg/net/hosts_test.go
に新しいテストケースTestSingleLineHostsFile
が追加されました。このテストは、末尾に改行がない単一行のホストファイル(testdata/hosts_singleline
)を作成し、lookupStaticHost
関数がそのファイルから正しいIPアドレスを解決できることを確認します。
コアとなるコードの変更箇所
src/pkg/net/hosts_test.go
--- a/src/pkg/net/hosts_test.go
+++ b/src/pkg/net/hosts_test.go
@@ -53,6 +53,19 @@ func TestLookupStaticHost(t *testing.T) {
hostsPath = p
}
+// https://code.google.com/p/go/issues/detail?id=6646
+func TestSingleLineHostsFile(t *testing.T) {
+ p := hostsPath
+ hostsPath = "testdata/hosts_singleline"
+
+ ips := lookupStaticHost("odin")
+ if len(ips) != 1 || ips[0] != "127.0.0.2" {
+ t.Errorf("lookupStaticHost = %v, want %v", ips, []string{"127.0.0.2"})
+ }
+
+ hostsPath = p
+}
+
func TestLookupHost(t *testing.T) {
// Can't depend on this to return anything in particular,
// but if it does return something, make sure it doesn't
src/pkg/net/parse.go
--- a/src/pkg/net/parse.go
+++ b/src/pkg/net/parse.go
@@ -54,7 +54,7 @@ func (f *file) readLine() (s string, ok bool) {
if n >= 0 {
f.data = f.data[0 : ln+n]
}
- if err == io.EOF {
+ if err == io.EOF || err == io.ErrUnexpectedEOF {
f.atEOF = true
}
}
src/pkg/net/testdata/hosts_singleline
(新規ファイル)
127.0.0.2 odin
\ No newline at end of file
コアとなるコードの解説
src/pkg/net/parse.go
の変更
readLine
関数内の以下の行が変更されました。
- if err == io.EOF {
+ if err == io.EOF || err == io.ErrUnexpectedEOF {
この変更により、f.r.ReadSlice('\n')
が返すエラーがio.EOF
またはio.ErrUnexpectedEOF
のいずれかである場合に、ファイルの終端(f.atEOF = true
)として扱われるようになります。これにより、末尾に改行がないファイルでも、その最後の行が正しく読み込まれ、処理が完了するようになります。
src/pkg/net/hosts_test.go
の変更
TestSingleLineHostsFile
という新しいテスト関数が追加されました。
このテストは以下の手順を実行します。
- 現在の
hostsPath
(ホストファイルのパス)を保存します。 hostsPath
を新しく作成されたテストデータファイルtestdata/hosts_singleline
に設定します。このファイルは127.0.0.2 odin
という単一行のみを含み、末尾に改行がありません。lookupStaticHost("odin")
を呼び出し、odin
というホスト名に対応するIPアドレスを検索します。- 返されたIPアドレスが期待される値(
127.0.0.2
)と一致するかどうかを検証します。 - 最後に、
hostsPath
を元の値に戻します。
このテストケースの追加により、末尾に改行がないホストファイルが正しくパースされることが保証されます。
関連リンク
- Go Issue #6646: https://code.google.com/p/go/issues/detail?id=6646 (ただし、このリンクは現在アクセスできない可能性があります。GoのIssueトラッカーはGitHubに移行しています。)
- Go CL 15960047: https://golang.org/cl/15960047
参考にした情報源リンク
- Go言語の公式ドキュメント
- Go言語のソースコード
- Go言語のIssueトラッカー (GitHub)
io
パッケージのドキュメントbufio
パッケージのドキュメント