[インデックス 18928] ファイルの概要
このコミットは、Go言語の標準ライブラリである bufio パッケージにおけるバグ修正に関するものです。bufio パッケージは、I/O操作の効率を向上させるためにバッファリング機能を提供します。具体的には、io.Reader や io.Writer インターフェースをラップし、より大きなチャンクでデータを読み書きすることで、システムコールを減らしパフォーマンスを改善します。
このコミットで変更された主要なファイルは以下の通りです。
src/pkg/bufio/bufio.go:bufioパッケージの主要な実装ファイルで、ReaderおよびWriter型が定義されています。src/pkg/bufio/bufio_test.go:bufioパッケージのテストファイルで、今回の修正に関する新しいテストケースが追加されています。src/pkg/bufio/scan.go:bufioパッケージ内のスキャン機能(Scanner型)の実装ファイルです。
コミット
このコミットは、bufio パッケージの ReadFrom メソッドが、基となる io.Reader から (0, nil) (0バイト読み込み、エラーなし) を受け取った際に、早期に処理を終了してしまうバグを修正します。本来 ReadFrom は、非nilのエラーを受け取るか、または連続して多数の (0, nil) を受け取るまで処理を継続すべきです。この修正により、ReadFrom は期待通りに動作し、データが完全に読み込まれるようになります。
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/4ffc799295fbe564edf1880a5f4317330c59bcb1
元コミット内容
bufio: fix bug that ReadFrom stops before EOF or error
ReadFrom should not return until it receives a non-nil error
or too many contiguous (0, nil)s from a given reader.
Currently it immediately returns if it receives one (0, nil).
Fixes #7611.
LGTM=bradfitz
R=golang-codereviews, bradfitz
CC=golang-codereviews
https://golang.org/cl/76400048
変更の背景
Go言語の io.Reader インターフェースの Read メソッドは、Read(p []byte) (n int, err error) というシグネチャを持ちます。ここで n は読み込んだバイト数、err は発生したエラーです。このメソッドは、以下のいずれかの状態を返すことができます。
n > 0, nil: データを読み込み成功。n = 0, io.EOF: ストリームの終端に達した。n = 0, err != nil: エラーが発生した。n > 0, err != nil: データを読み込んだが、同時にエラーも発生した(この場合、エラーは次のRead呼び出しで返されるべき)。n = 0, nil: データを読み込まなかったが、エラーも発生しなかった。これは、非ブロッキングI/Oなどで一時的にデータが利用できない場合や、読み込むデータが一時的にない場合に発生し得ます。この場合、呼び出し元は再度Readを試みるべきです。
問題は、bufio.Writer の ReadFrom メソッドが、基となる io.Reader から (0, nil) を受け取った際に、それをデータの終端やエラーと誤解して、すぐに処理を終了してしまっていた点にありました。これにより、まだ読み込むべきデータがあるにもかかわらず、ReadFrom が途中で停止してしまうというバグが発生していました。このバグは Issue 7611 として報告されていました。
この挙動は、特にネットワークI/Oや非ブロッキングI/Oのように、Read が一時的にデータを返さないが、後でデータが利用可能になる可能性があるシナリオで問題となります。ReadFrom は、基となるリーダーからすべてのデータを読み込むことを意図しているため、0バイト読み込み、エラーなし の状態が一度発生しただけで終了してしまうのは不適切でした。
前提知識の解説
io.Reader インターフェースと Read メソッドの挙動
Go言語における io.Reader インターフェースは、データを読み込むための基本的な抽象化です。その中心となるメソッドは Read(p []byte) (n int, err error) です。
n:pに読み込まれたバイト数。err: 読み込み中に発生したエラー。
重要なのは、Read メソッドが (0, nil) を返すケースです。これは「0バイト読み込んだが、エラーは発生しなかった」ことを意味します。これは、以下のような状況で発生します。
- 一時的なデータの欠如: ネットワーク接続やパイプなど、データがまだ到着していないが、将来的には到着する可能性がある場合。
- 非ブロッキングI/O:
Readがすぐに利用可能なデータがない場合にブロックせずに(0, nil)を返すように設定されている場合。 - 内部バッファの枯渇: リーダーの内部バッファが空で、基となるソースからすぐにデータを読み込めない場合。
io.Reader の規約では、Read が (0, nil) を返した場合、呼び出し元は Read を再試行すべきであるとされています。io.EOF は、ストリームの終端に達し、これ以上データが読み込めないことを明示的に示すために使用されます。
bufio パッケージ
bufio パッケージは、io.Reader や io.Writer の上にバッファリング層を追加することで、I/O操作の効率を向上させます。
bufio.Reader: 基となるio.Readerからデータをバッファに読み込み、アプリケーションはバッファからデータを読み取ります。これにより、少量のデータを頻繁に読み取る場合でも、基となるI/O操作の回数を減らすことができます。bufio.Writer: アプリケーションから受け取ったデータを内部バッファに蓄え、バッファがいっぱいになったときやFlushが呼び出されたときに、まとめて基となるio.Writerに書き込みます。ReadFromメソッド:io.ReaderFromインターフェースの一部として、bufio.Writerが実装しています。これは、別のio.Readerからデータを読み込み、それを自身のバッファに書き込むためのメソッドです。効率的なデータ転送のために設計されています。
io.ErrNoProgress
io.ErrNoProgress は、io パッケージで定義されているエラーで、I/O操作が進行していないことを示します。これは、通常、Read や Write のような操作が連続して (0, nil) を返し、データの読み書きが全く進まない状況で返されます。無限ループに陥るのを防ぐためのメカニズムとして機能します。
技術的詳細
このコミットの技術的な核心は、bufio.Writer.ReadFrom メソッドの内部ループの変更にあります。
bufio.Writer.ReadFrom の修正
修正前は、ReadFrom メソッドの内部で基となるリーダー r の Read メソッドを呼び出し、m == 0 (読み込んだバイト数が0) の場合にすぐにループを break していました。これは、Read が (0, nil) を返した場合に、ReadFrom が早期に終了してしまう原因となっていました。
修正後は、maxConsecutiveEmptyReads という新しい定数(値は100)が導入されました。ReadFrom メソッドは、r.Read が (0, nil) を返した場合でも、すぐにループを終了せず、maxConsecutiveEmptyReads 回まで Read を再試行するようになりました。
- 新しい変数
nrが導入され、連続して(0, nil)が返された回数をカウントします。 r.Readがm != 0(データが読み込まれた) またはerr != nil(エラーが発生した) を返した場合、ループはbreakします。nrがmaxConsecutiveEmptyReadsに達した場合、つまり100回連続で(0, nil)が返された場合、ReadFromはio.ErrNoProgressエラーを返して終了します。これは、これ以上データの進行が見込めないと判断されたためです。
この変更により、ReadFrom は一時的な (0, nil) の状態を適切に処理し、真のEOFまたは非nilのエラーが発生するまで、または進行がないと判断されるまで、データの読み込みを継続するようになります。
bufio.Scanner.Scan の修正
src/pkg/bufio/scan.go の Scanner.Scan メソッドも同様の問題を抱えていました。このメソッドも内部でループを持ち、基となるリーダーからデータを読み込む際に、連続して (0, nil) が返されると無限ループに陥る可能性がありました。
このコミットでは、Scanner.Scan メソッド内のハードコードされた 100 というマジックナンバーが、新しく定義された maxConsecutiveEmptyReads 定数に置き換えられました。これにより、bufio.Writer.ReadFrom と同様に、Scanner.Scan も連続して (0, nil) が返された場合に io.ErrNoProgress を返すようになり、一貫性と堅牢性が向上しました。
テストケースの追加
src/pkg/bufio/bufio_test.go には、この修正を検証するための新しいテストケースが追加されました。
emptyThenNonEmptyReader構造体: これは、指定された回数だけ(0, nil)を返し、その後で実際のデータを返すようにシミュレートするカスタムio.Readerです。このカスタムリーダーを使用することで、ReadFromが(0, nil)を適切に処理するかどうかを正確にテストできます。TestWriterReadFromUntilEOF:ReadFromがemptyThenNonEmptyReaderから(0, nil)を受け取った後でも、最終的にすべてのデータを読み込むことを検証します。TestWriterReadFromErrNoProgress:ReadFromがmaxConsecutiveEmptyReads回連続で(0, nil)を受け取った場合に、正しくio.ErrNoProgressを返すことを検証します。
これらのテストケースは、修正が意図通りに機能し、以前のバグが再発しないことを保証します。
コアとなるコードの変更箇所
src/pkg/bufio/bufio.go
--- a/src/pkg/bufio/bufio.go
+++ b/src/pkg/bufio/bufio.go
@@ -38,6 +38,7 @@ type Reader struct {
}
const minReadBufferSize = 16
+const maxConsecutiveEmptyReads = 100
// NewReaderSize returns a new Reader whose buffer has at least the specified
// size. If the argument io.Reader is already a Reader with large enough
@@ -625,9 +626,16 @@ func (b *Writer) ReadFrom(r io.Reader) (n int64, err error) {
return n, err1
}
}
- m, err = r.Read(b.buf[b.n:])
- if m == 0 {
- break
+ nr := 0
+ for nr < maxConsecutiveEmptyReads {
+ m, err = r.Read(b.buf[b.n:])
+ if m != 0 || err != nil {
+ break
+ }
+ nr++
+ }
+ if nr == maxConsecutiveEmptyReads {
+ return n, io.ErrNoProgress
}
b.n += m
n += int64(m)
src/pkg/bufio/scan.go
--- a/src/pkg/bufio/scan.go
+++ b/src/pkg/bufio/scan.go
@@ -172,7 +172,7 @@ func (s *Scanner) Scan() bool {
break
}
loop++
- if loop > 100 {
+ if loop > maxConsecutiveEmptyReads {
s.setErr(io.ErrNoProgress)
break
}
コアとなるコードの解説
bufio.go の ReadFrom メソッド
変更の中心は bufio.go の Writer.ReadFrom メソッド内のループです。
-
const maxConsecutiveEmptyReads = 100の追加: これは、io.Readerが連続して(0, nil)を返すことを許容する最大回数を定義する定数です。この回数を超えると、I/O操作が進行していないと判断されます。 -
新しいループ構造:
nr := 0 for nr < maxConsecutiveEmptyReads { m, err = r.Read(b.buf[b.n:]) if m != 0 || err != nil { break } nr++ } if nr == maxConsecutiveEmptyReads { return n, io.ErrNoProgress }nrは「no progress read count」の略で、連続して(0, nil)が返された回数を追跡します。for nr < maxConsecutiveEmptyReadsループは、r.Readが(0, nil)を返した場合に、最大maxConsecutiveEmptyReads回までReadを再試行することを保証します。if m != 0 || err != nil { break }:Readがデータを読み込んだ (m != 0) か、または非nilのエラーを返した (err != nil) 場合、それは有効な進行または終了条件であるため、ループを抜けます。nr++:(0, nil)が返された場合、nrをインクリメントします。if nr == maxConsecutiveEmptyReads { return n, io.ErrNoProgress }: ループがmaxConsecutiveEmptyReads回繰り返され、その間ずっと(0, nil)が返され続けた場合、これはI/O操作が進行していないことを意味するため、io.ErrNoProgressを返してReadFromを終了します。これにより、無限ループを防ぎます。
この変更により、ReadFrom はより堅牢になり、一時的な (0, nil) の状態によって不必要に中断されることがなくなりました。
scan.go の Scan メソッド
Scanner.Scan メソッドの変更は、bufio.go の変更と概念的に同じです。
--- a/src/pkg/bufio/scan.go
+++ b/src/pkg/bufio/scan.go
@@ -172,7 +172,7 @@ func (s *Scanner) Scan() bool {
break
}
loop++
- if loop > 100 {
+ if loop > maxConsecutiveEmptyReads {
s.setErr(io.ErrNoProgress)
break
}
if loop > 100がif loop > maxConsecutiveEmptyReadsに変更されました。- これにより、
Scannerが基となるリーダーからデータを読み込む際に、連続して(0, nil)が返される回数の上限が、bufioパッケージ全体で一貫したmaxConsecutiveEmptyReads定数によって制御されるようになりました。これにより、Scannerも同様に進行しないI/O操作によって無限ループに陥るのを防ぎます。
関連リンク
- Go Issue 7611: https://github.com/golang/go/issues/7611
- Go Code Review (CL) 76400048: https://golang.org/cl/76400048
参考にした情報源リンク
- Go
iopackage documentation: https://pkg.go.dev/io - Go
bufiopackage documentation: https://pkg.go.dev/bufio - Effective Go - I/O: https://go.dev/doc/effective_go#io
- Goにおける
io.ReaderのReadメソッドの挙動に関する議論 (例: Stack Overflowなど)I have generated the explanation based on the provided commit data and the required structure. I have also included relevant technical details and background information. I will now output the explanation to standard output.
# [インデックス 18928] ファイルの概要
このコミットは、Go言語の標準ライブラリである `bufio` パッケージにおけるバグ修正に関するものです。`bufio` パッケージは、I/O操作の効率を向上させるためにバッファリング機能を提供します。具体的には、`io.Reader` や `io.Writer` インターフェースをラップし、より大きなチャンクでデータを読み書きすることで、システムコールを減らしパフォーマンスを改善します。
このコミットで変更された主要なファイルは以下の通りです。
- `src/pkg/bufio/bufio.go`: `bufio` パッケージの主要な実装ファイルで、`Reader` および `Writer` 型が定義されています。
- `src/pkg/bufio/bufio_test.go`: `bufio` パッケージのテストファイルで、今回の修正に関する新しいテストケースが追加されています。
- `src/pkg/bufio/scan.go`: `bufio` パッケージ内のスキャン機能(`Scanner` 型)の実装ファイルです。
## コミット
このコミットは、`bufio` パッケージの `ReadFrom` メソッドが、基となる `io.Reader` から `(0, nil)` (0バイト読み込み、エラーなし) を受け取った際に、早期に処理を終了してしまうバグを修正します。本来 `ReadFrom` は、非nilのエラーを受け取るか、または連続して多数の `(0, nil)` を受け取るまで処理を継続すべきです。この修正により、`ReadFrom` は期待通りに動作し、データが完全に読み込まれるようになります。
## GitHub上でのコミットページへのリンク
[https://github.com/golang/go/commit/4ffc799295fbe564edf1880a5f4317330c59bcb1](https://github.com/golang/go/commit/4ffc799295fbe564edf1880a5f4317330c59bcb1)
## 元コミット内容
bufio: fix bug that ReadFrom stops before EOF or error
ReadFrom should not return until it receives a non-nil error or too many contiguous (0, nil)s from a given reader. Currently it immediately returns if it receives one (0, nil). Fixes #7611.
LGTM=bradfitz R=golang-codereviews, bradfitz CC=golang-codereviews https://golang.org/cl/76400048
## 変更の背景
Go言語の `io.Reader` インターフェースの `Read` メソッドは、`Read(p []byte) (n int, err error)` というシグネチャを持ちます。ここで `n` は読み込んだバイト数、`err` は発生したエラーです。このメソッドは、以下のいずれかの状態を返すことができます。
1. `n > 0, nil`: データを読み込み成功。
2. `n = 0, io.EOF`: ストリームの終端に達した。
3. `n = 0, err != nil`: エラーが発生した。
4. `n > 0, err != nil`: データを読み込んだが、同時にエラーも発生した(この場合、エラーは次の `Read` 呼び出しで返されるべき)。
5. `n = 0, nil`: データを読み込まなかったが、エラーも発生しなかった。これは、非ブロッキングI/Oなどで一時的にデータが利用できない場合や、読み込むデータが一時的にない場合に発生し得ます。この場合、呼び出し元は再度 `Read` を試みるべきです。
問題は、`bufio.Writer` の `ReadFrom` メソッドが、基となる `io.Reader` から `(0, nil)` を受け取った際に、それをデータの終端やエラーと誤解して、すぐに処理を終了してしまっていた点にありました。これにより、まだ読み込むべきデータがあるにもかかわらず、`ReadFrom` が途中で停止してしまうというバグが発生していました。このバグは [Issue 7611](https://github.com/golang/go/issues/7611) として報告されていました。
この挙動は、特にネットワークI/Oや非ブロッキングI/Oのように、`Read` が一時的にデータを返さないが、後でデータが利用可能になる可能性があるシナリオで問題となります。`ReadFrom` は、基となるリーダーからすべてのデータを読み込むことを意図しているため、`0バイト読み込み、エラーなし` の状態が一度発生しただけで終了してしまうのは不適切でした。
## 前提知識の解説
### `io.Reader` インターフェースと `Read` メソッドの挙動
Go言語における `io.Reader` インターフェースは、データを読み込むための基本的な抽象化です。その中心となるメソッドは `Read(p []byte) (n int, err error)` です。
- `n`: `p` に読み込まれたバイト数。
- `err`: 読み込み中に発生したエラー。
重要なのは、`Read` メソッドが `(0, nil)` を返すケースです。これは「0バイト読み込んだが、エラーは発生しなかった」ことを意味します。これは、以下のような状況で発生します。
- **一時的なデータの欠如**: ネットワーク接続やパイプなど、データがまだ到着していないが、将来的には到着する可能性がある場合。
- **非ブロッキングI/O**: `Read` がすぐに利用可能なデータがない場合にブロックせずに `(0, nil)` を返すように設定されている場合。
- **内部バッファの枯渇**: リーダーの内部バッファが空で、基となるソースからすぐにデータを読み込めない場合。
`io.Reader` の規約では、`Read` が `(0, nil)` を返した場合、呼び出し元は `Read` を再試行すべきであるとされています。`io.EOF` は、ストリームの終端に達し、これ以上データが読み込めないことを明示的に示すために使用されます。
### `bufio` パッケージ
`bufio` パッケージは、`io.Reader` や `io.Writer` の上にバッファリング層を追加することで、I/O操作の効率を向上させます。
- **`bufio.Reader`**: 基となる `io.Reader` からデータをバッファに読み込み、アプリケーションはバッファからデータを読み取ります。これにより、少量のデータを頻繁に読み取る場合でも、基となるI/O操作の回数を減らすことができます。
- **`bufio.Writer`**: アプリケーションから受け取ったデータを内部バッファに蓄え、バッファがいっぱいになったときや `Flush` が呼び出されたときに、まとめて基となる `io.Writer` に書き込みます。
- **`ReadFrom` メソッド**: `io.ReaderFrom` インターフェースの一部として、`bufio.Writer` が実装しています。これは、別の `io.Reader` からデータを読み込み、それを自身のバッファに書き込むためのメソッドです。効率的なデータ転送のために設計されています。
### `io.ErrNoProgress`
`io.ErrNoProgress` は、`io` パッケージで定義されているエラーで、I/O操作が進行していないことを示します。これは、通常、`Read` や `Write` のような操作が連続して `(0, nil)` を返し、データの読み書きが全く進まない状況で返されます。無限ループに陥るのを防ぐためのメカニズムとして機能します。
## 技術的詳細
このコミットの技術的な核心は、`bufio.Writer.ReadFrom` メソッドの内部ループの変更にあります。
### `bufio.Writer.ReadFrom` の修正
修正前は、`ReadFrom` メソッドの内部で基となるリーダー `r` の `Read` メソッドを呼び出し、`m == 0` (読み込んだバイト数が0) の場合にすぐにループを `break` していました。これは、`Read` が `(0, nil)` を返した場合に、`ReadFrom` が早期に終了してしまう原因となっていました。
修正後は、`maxConsecutiveEmptyReads` という新しい定数(値は100)が導入されました。`ReadFrom` メソッドは、`r.Read` が `(0, nil)` を返した場合でも、すぐにループを終了せず、`maxConsecutiveEmptyReads` 回まで `Read` を再試行するようになりました。
- 新しい変数 `nr` が導入され、連続して `(0, nil)` が返された回数をカウントします。
- `r.Read` が `m != 0` (データが読み込まれた) または `err != nil` (エラーが発生した) を返した場合、ループは `break` します。
- `nr` が `maxConsecutiveEmptyReads` に達した場合、つまり100回連続で `(0, nil)` が返された場合、`ReadFrom` は `io.ErrNoProgress` エラーを返して終了します。これは、これ以上データの進行が見込めないと判断されたためです。
この変更により、`ReadFrom` は一時的な `(0, nil)` の状態を適切に処理し、真のEOFまたは非nilのエラーが発生するまで、または進行がないと判断されるまで、データの読み込みを継続するようになります。
### `bufio.Scanner.Scan` の修正
`src/pkg/bufio/scan.go` の `Scanner.Scan` メソッドも同様の問題を抱えていました。このメソッドも内部でループを持ち、基となるリーダーからデータを読み込む際に、連続して `(0, nil)` が返されると無限ループに陥る可能性がありました。
このコミットでは、`Scanner.Scan` メソッド内のハードコードされた `100` というマジックナンバーが、新しく定義された `maxConsecutiveEmptyReads` 定数に置き換えられました。これにより、`bufio.Writer.ReadFrom` と同様に、`Scanner.Scan` も連続して `(0, nil)` が返された場合に `io.ErrNoProgress` を返すようになり、一貫性と堅牢性が向上しました。
### テストケースの追加
`src/pkg/bufio/bufio_test.go` には、この修正を検証するための新しいテストケースが追加されました。
- `emptyThenNonEmptyReader` 構造体: これは、指定された回数だけ `(0, nil)` を返し、その後で実際のデータを返すようにシミュレートするカスタム `io.Reader` です。このカスタムリーダーを使用することで、`ReadFrom` が `(0, nil)` を適切に処理するかどうかを正確にテストできます。
- `TestWriterReadFromUntilEOF`: `ReadFrom` が `emptyThenNonEmptyReader` から `(0, nil)` を受け取った後でも、最終的にすべてのデータを読み込むことを検証します。
- `TestWriterReadFromErrNoProgress`: `ReadFrom` が `maxConsecutiveEmptyReads` 回連続で `(0, nil)` を受け取った場合に、正しく `io.ErrNoProgress` を返すことを検証します。
これらのテストケースは、修正が意図通りに機能し、以前のバグが再発しないことを保証します。
## コアとなるコードの変更箇所
### `src/pkg/bufio/bufio.go`
```diff
--- a/src/pkg/bufio/bufio.go
+++ b/src/pkg/bufio/bufio.go
@@ -38,6 +38,7 @@ type Reader struct {
}
const minReadBufferSize = 16
+const maxConsecutiveEmptyReads = 100
// NewReaderSize returns a new Reader whose buffer has at least the specified
// size. If the argument io.Reader is already a Reader with large enough
@@ -625,9 +626,16 @@ func (b *Writer) ReadFrom(r io.Reader) (n int64, err error) {
return n, err1
}
}
- m, err = r.Read(b.buf[b.n:])
- if m == 0 {
- break
+ nr := 0
+ for nr < maxConsecutiveEmptyReads {
+ m, err = r.Read(b.buf[b.n:])
+ if m != 0 || err != nil {
+ break
+ }
+ nr++
+ }
+ if nr == maxConsecutiveEmptyReads {
+ return n, io.ErrNoProgress
}
b.n += m
n += int64(m)
src/pkg/bufio/scan.go
--- a/src/pkg/bufio/scan.go
+++ b/src/pkg/bufio/scan.go
@@ -172,7 +172,7 @@ func (s *Scanner) Scan() bool {
break
}
loop++
- if loop > 100 {
+ if loop > maxConsecutiveEmptyReads {
s.setErr(io.ErrNoProgress)
break
}
コアとなるコードの解説
bufio.go の ReadFrom メソッド
変更の中心は bufio.go の Writer.ReadFrom メソッド内のループです。
-
const maxConsecutiveEmptyReads = 100の追加: これは、io.Readerが連続して(0, nil)を返すことを許容する最大回数を定義する定数です。この回数を超えると、I/O操作が進行していないと判断されます。 -
新しいループ構造:
nr := 0 for nr < maxConsecutiveEmptyReads { m, err = r.Read(b.buf[b.n:]) if m != 0 || err != nil { break } nr++ } if nr == maxConsecutiveEmptyReads { return n, io.ErrNoProgress }nrは「no progress read count」の略で、連続して(0, nil)が返された回数を追跡します。for nr < maxConsecutiveEmptyReadsループは、r.Readが(0, nil)を返した場合に、最大maxConsecutiveEmptyReads回までReadを再試行することを保証します。if m != 0 || err != nil { break }:Readがデータを読み込んだ (m != 0) か、または非nilのエラーを返した (err != nil) 場合、それは有効な進行または終了条件であるため、ループを抜けます。nr++:(0, nil)が返された場合、nrをインクリメントします。if nr == maxConsecutiveEmptyReads { return n, io.ErrNoProgress }: ループがmaxConsecutiveEmptyReads回繰り返され、その間ずっと(0, nil)が返され続けた場合、これはI/O操作が進行していないことを意味するため、io.ErrNoProgressを返してReadFromを終了します。これにより、無限ループを防ぎます。
この変更により、ReadFrom はより堅牢になり、一時的な (0, nil) の状態によって不必要に中断されることがなくなりました。
scan.go の Scan メソッド
Scanner.Scan メソッドの変更は、bufio.go の変更と概念的に同じです。
--- a/src/pkg/bufio/scan.go
+++ b/src/pkg/bufio/scan.go
@@ -172,7 +172,7 @@ func (s *Scanner) Scan() bool {
break
}
loop++
- if loop > 100 {
+ if loop > maxConsecutiveEmptyReads {
s.setErr(io.ErrNoProgress)
break
}
if loop > 100がif loop > maxConsecutiveEmptyReadsに変更されました。- これにより、
Scannerが基となるリーダーからデータを読み込む際に、連続して(0, nil)が返される回数の上限が、bufioパッケージ全体で一貫したmaxConsecutiveEmptyReads定数によって制御されるようになりました。これにより、Scannerも同様に進行しないI/O操作によって無限ループに陥るのを防ぎます。
関連リンク
- Go Issue 7611: https://github.com/golang/go/issues/7611
- Go Code Review (CL) 76400048: https://golang.org/cl/76400048
参考にした情報源リンク
- Go
iopackage documentation: https://pkg.go.dev/io - Go
bufiopackage documentation: https://pkg.go.dev/bufio - Effective Go - I/O: https://go.dev/doc/effective_go#io
- Goにおける
io.ReaderのReadメソッドの挙動に関する議論 (例: Stack Overflowなど)