From 9ec32a9e7b2a39103c905d57e270d99463e6aa99 Mon Sep 17 00:00:00 2001
From: Or Neeman <oneeman@gmail.com>
Date: Thu, 18 Feb 2021 03:19:49 -0600
Subject: [PATCH] rlp: handle case of normal EOF in Stream.readFull (#22336)

io.Reader may return n > 0 and io.EOF at the end of the input stream.
readFull did not handle this correctly, looking only at the error. This fixes
it to check for n == len(buf) as well.
---
 rlp/decode.go      |  8 +++++++-
 rlp/decode_test.go | 20 ++++++++++++++++++++
 2 files changed, 27 insertions(+), 1 deletion(-)

diff --git a/rlp/decode.go b/rlp/decode.go
index 5f3f5eedf..79b7ef062 100644
--- a/rlp/decode.go
+++ b/rlp/decode.go
@@ -952,7 +952,13 @@ func (s *Stream) readFull(buf []byte) (err error) {
 		n += nn
 	}
 	if err == io.EOF {
-		err = io.ErrUnexpectedEOF
+		if n < len(buf) {
+			err = io.ErrUnexpectedEOF
+		} else {
+			// Readers are allowed to give EOF even though the read succeeded.
+			// In such cases, we discard the EOF, like io.ReadFull() does.
+			err = nil
+		}
 	}
 	return err
 }
diff --git a/rlp/decode_test.go b/rlp/decode_test.go
index 167e9974b..d94c3969b 100644
--- a/rlp/decode_test.go
+++ b/rlp/decode_test.go
@@ -665,6 +665,26 @@ func TestDecodeWithByteReader(t *testing.T) {
 	})
 }
 
+func testDecodeWithEncReader(t *testing.T, n int) {
+	s := strings.Repeat("0", n)
+	_, r, _ := EncodeToReader(s)
+	var decoded string
+	err := Decode(r, &decoded)
+	if err != nil {
+		t.Errorf("Unexpected decode error with n=%v: %v", n, err)
+	}
+	if decoded != s {
+		t.Errorf("Decode mismatch with n=%v", n)
+	}
+}
+
+// This is a regression test checking that decoding from encReader
+// works for RLP values of size 8192 bytes or more.
+func TestDecodeWithEncReader(t *testing.T) {
+	testDecodeWithEncReader(t, 8188) // length with header is 8191
+	testDecodeWithEncReader(t, 8189) // length with header is 8192
+}
+
 // plainReader reads from a byte slice but does not
 // implement ReadByte. It is also not recognized by the
 // size validation. This is useful to test how the decoder
-- 
GitLab