Skip to content

v1.3.0 Decoder doesn't process read data if underlying reader returns io.EOF #425

@cixel

Description

@cixel

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)
	}
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions