From 32fccdfb4e8c2462ea5767bcc195ad1052548b93 Mon Sep 17 00:00:00 2001 From: gammazero Date: Fri, 31 Mar 2023 23:03:36 -0700 Subject: [PATCH 1/4] CidFromReader should not wrap valid EOF return. When reading from an io.Reader that has no data, the io.EOF error should not be wrapped in ErrInvalidCid. This is not an invalid CID, and is not the same as a partial read which is indicated by io.ErrUnexpectedEOF. This fix is needed because existing code that uses CidFromReader may check for the end of an input stream by `if err == io.EOF` instead of the preferred `if errors.Is(err, io.EOF)`, and that code break at runtime after upgrading to go-cid v0.4.0. --- cid.go | 4 ++++ cid_test.go | 14 ++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/cid.go b/cid.go index ae3d1fd..cc7c4b1 100644 --- a/cid.go +++ b/cid.go @@ -727,6 +727,10 @@ func CidFromReader(r io.Reader) (int, Cid, error) { // The varint package wants a io.ByteReader, so we must wrap our io.Reader. vers, err := varint.ReadUvarint(br) if err != nil { + if err == io.EOF { + // No data; not an invalid CID. + return 0, Undef, err + } return len(br.dst), Undef, ErrInvalidCid{err} } diff --git a/cid_test.go b/cid_test.go index 31989da..f0c6ad5 100644 --- a/cid_test.go +++ b/cid_test.go @@ -783,6 +783,20 @@ func TestBadCidInput(t *testing.T) { } } +func TestFromReaderNoData(t *testing.T) { + // Reading no data from io.Reader should return io.EOF, not ErrInvalidCid. + n, cid, err := CidFromReader(bytes.NewReader(nil)) + if err != io.EOF { + t.Fatal("Expected io.EOF error") + } + if cid != Undef { + t.Fatal("Expected Undef CID") + } + if n != 0 { + t.Fatal("Expected 0 data") + } +} + func TestBadParse(t *testing.T) { hash, err := mh.Sum([]byte("foobar"), mh.SHA3_256, -1) if err != nil { From 215c3101307728adcdc012d5e2e8c40eab611a4f Mon Sep 17 00:00:00 2001 From: Andrew Gillis Date: Mon, 3 Apr 2023 07:50:51 -0700 Subject: [PATCH 2/4] Update cid.go Co-authored-by: Rod Vagg --- cid.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cid.go b/cid.go index cc7c4b1..6e36764 100644 --- a/cid.go +++ b/cid.go @@ -728,7 +728,8 @@ func CidFromReader(r io.Reader) (int, Cid, error) { vers, err := varint.ReadUvarint(br) if err != nil { if err == io.EOF { - // No data; not an invalid CID. + // First-byte read in ReadUvarint errors with io.EOF, so reader has no data. + // Subsequent reads with an EOF will return io.ErrUnexpectedEOF and be wrapped here. return 0, Undef, err } return len(br.dst), Undef, ErrInvalidCid{err} From 84da2546f80a40c2c171fdcd95a2227da5822266 Mon Sep 17 00:00:00 2001 From: gammazero Date: Mon, 3 Apr 2023 08:18:57 -0700 Subject: [PATCH 3/4] Add unit test for unexpected eof --- cid.go | 3 +++ cid_test.go | 10 ++++++++++ 2 files changed, 13 insertions(+) diff --git a/cid.go b/cid.go index 6e36764..f182424 100644 --- a/cid.go +++ b/cid.go @@ -717,6 +717,9 @@ func (r *bufByteReader) ReadByte() (byte, error) { // It's recommended to supply a reader that buffers and implements io.ByteReader, // as CidFromReader has to do many single-byte reads to decode varints. // If the argument only implements io.Reader, single-byte Read calls are used instead. +// +// If the Reader is found to yield zero bytes, an io.EOF error is returned directly, in all +// other error cases, an ErrInvalidCid, wrapping the original error, is returned. func CidFromReader(r io.Reader) (int, Cid, error) { // 64 bytes is enough for any CIDv0, // and it's enough for most CIDv1s in practice. diff --git a/cid_test.go b/cid_test.go index f0c6ad5..36fba76 100644 --- a/cid_test.go +++ b/cid_test.go @@ -795,6 +795,16 @@ func TestFromReaderNoData(t *testing.T) { if n != 0 { t.Fatal("Expected 0 data") } + + // Read byte indicatiing more data to and check error is ErrInvalidCid. + _, _, err = CidFromReader(bytes.NewReader([]byte{0x80})) + if !errors.Is(err, ErrInvalidCid{}) { + t.Fatal("Expected ErrInvalidCid error") + } + // Check for expected wrapped error. + if !errors.Is(err, io.ErrUnexpectedEOF) { + t.Fatal("Expected error", io.ErrUnexpectedEOF) + } } func TestBadParse(t *testing.T) { From a245227c15a53db609c5c405bc9c4b8bcf2264bd Mon Sep 17 00:00:00 2001 From: Rod Vagg Date: Tue, 4 Apr 2023 13:51:46 +1000 Subject: [PATCH 4/4] v0.4.1 --- version.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.json b/version.json index 372b6ea..26a7d47 100644 --- a/version.json +++ b/version.json @@ -1,3 +1,3 @@ { - "version": "v0.4.0" + "version": "v0.4.1" }