48354


以下のように無限に2バイトを返し続ける`io.Reader`を実装して、そこから奇数バイト（例では5バイト）を`io.CopyN`でコピーしようとするとpanicを起こしました。偶数バイトをコピーする場合には起きません。なぜでしょうか？

[code]

    package main
    
    import (
        "io"
        "os"
    )
    
    type stream int
    
    func (s *stream) Read(p []byte) (n int, err error) {
        p[0] = byte('a')
        p[1] = byte('b')
        return 2, nil
    }
    
    func main() {
        io.CopyN(os.Stdout, new(stream), 5)
        // panic: runtime error: index out of range
    }
    
[/code]

環境：go version go1.10.3 windows/386


CC BY-SA 4.0
2018-09-12T08:15:21.767
48310
2018-09-13T04:38:57.217
19759
question
go
無限に2バイトを返すio.Readerからio.CopyNで奇数バイトをコピーするとpanic


自己回答です。（metropolisさんのコメントから）

`io.CopyN` 関数は、受け取った `io.Reader` を `io.LimitedReader` でラップしてから `io.Copy`
に渡してコピーしています。

今回の例ですと、`io.LimitedReader` はラップした `io.Reader` から、以下のバッファサイズでreadします。

  * １回目のread：5バイト（そして2バイト読み込む）
  * ２回目のread：3バイト（そして2バイト読み込む）
  * ３回目のread：1バイト

３回目のreadではバッファサイズは1バイトであるため、`p[1]` にアクセスしようとして `index out of range` が発生します。

正しくは、受け取ったバッファ `p` が必要なサイズを満たしているかどうかをチェックするべきです。


CC BY-SA 4.0
2018-09-13T04:38:57.217
48354
2018-09-13T04:38:57.217
19759
48310
answer