-
Notifications
You must be signed in to change notification settings - Fork 305
v1.3.0 Decoder doesn't process read data if underlying reader returns io.EOF #425
Description
v1.3.0 seems to handle io.EOF differently than the previous release did. There is a reproducer below the break which illustrates the issue.
The io.Reader docs say:
When Read encounters an error or end-of-file condition after successfully reading n > 0 bytes, it returns the number of bytes read. It may return the (non-nil) error from the same call or return the error (and n == 0) from a subsequent call. An instance of this general case is that a Reader returning a non-zero number of bytes at the end of the input stream may return either err == EOF or err == nil. The next Read should return 0, EOF.
An example of a Reader which returns n, io.EOF is *http.body.
Before v1.3.0, decoders seemed to explicitly check for io.EOF in io.REaderByteScannerT.Read here, but the current implementation doesn't seem to make this check and the result is that io.EOF is returned instead of nil. Additionally, the Read which returned EOF isn't used and so the Decode won't complete, so the end user can't simply choose to check and ignore io.EOF themselves.
package main
import (
"bytes"
"fmt"
"io"
"github.com/ugorji/go/codec"
)
type T struct {
S string
B []byte
}
type R struct {
i int
s []byte
}
func (r *R) Read(p []byte) (n int, err error) {
if r.i >= len(r.s) {
return 0, io.EOF
}
n = copy(p, r.s[r.i:])
r.i += n
if r.i == len(r.s) {
err = io.EOF
}
return
}
func main() {
buf := new(bytes.Buffer)
if err := codec.NewEncoder(buf, new(codec.MsgpackHandle)).Encode(&T{
S: "string",
B: []byte("bytes"),
}); err != nil {
panic(err)
}
r := &R{s: buf.Bytes()}
var t T
if err := codec.NewDecoder(r, new(codec.MsgpackHandle)).Decode(&t); err != nil {
fmt.Println(t) // note that T.B is empty
panic(err)
}
}