Skip to content

Commit 1ea796e

Browse files
Mark Ryanbradfitz
authored andcommitted
encoding/base32: ensure base32 decoder propagates errors correctly
A number of issues in decoder.Read and newlineFilteringReader.Read were preventing errors from the reader supplying the encoded data from being propagated to the caller. Fixing these issues revealed some additional problems in which valid decoded data was not always returned to the user when errors were actually propagated. This commit fixes both the error propagation and the lost decoded data problems. It also adds some new unit tests to ensure errors are handled correctly by decoder.Read. The new unit tests increase the test coverage of this package from 96.2% to 97.9%. Fixes golang#20044 Change-Id: I1a8632da20135906e2d191c2a8825b10e7ecc4c5 Reviewed-on: https://go-review.googlesource.com/42094 Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org> Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org>
1 parent 26a8521 commit 1ea796e

File tree

2 files changed

+188
-8
lines changed

2 files changed

+188
-8
lines changed

src/encoding/base32/base32.go

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -343,18 +343,33 @@ type decoder struct {
343343
outbuf [1024 / 8 * 5]byte
344344
}
345345

346-
func (d *decoder) Read(p []byte) (n int, err error) {
347-
if d.err != nil {
348-
return 0, d.err
346+
func readEncodedData(r io.Reader, buf []byte, min int) (n int, err error) {
347+
for n < min && err == nil {
348+
var nn int
349+
nn, err = r.Read(buf[n:])
350+
n += nn
351+
}
352+
if n < min && n > 0 && err == io.EOF {
353+
err = io.ErrUnexpectedEOF
349354
}
355+
return
356+
}
350357

358+
func (d *decoder) Read(p []byte) (n int, err error) {
351359
// Use leftover decoded output from last read.
352360
if len(d.out) > 0 {
353361
n = copy(p, d.out)
354362
d.out = d.out[n:]
363+
if len(d.out) == 0 {
364+
return n, d.err
365+
}
355366
return n, nil
356367
}
357368

369+
if d.err != nil {
370+
return 0, d.err
371+
}
372+
358373
// Read a chunk.
359374
nn := len(p) / 5 * 8
360375
if nn < 8 {
@@ -363,7 +378,8 @@ func (d *decoder) Read(p []byte) (n int, err error) {
363378
if nn > len(d.buf) {
364379
nn = len(d.buf)
365380
}
366-
nn, d.err = io.ReadAtLeast(d.r, d.buf[d.nbuf:nn], 8-d.nbuf)
381+
382+
nn, d.err = readEncodedData(d.r, d.buf[d.nbuf:nn], 8-d.nbuf)
367383
d.nbuf += nn
368384
if d.nbuf < 8 {
369385
return 0, d.err
@@ -373,21 +389,30 @@ func (d *decoder) Read(p []byte) (n int, err error) {
373389
nr := d.nbuf / 8 * 8
374390
nw := d.nbuf / 8 * 5
375391
if nw > len(p) {
376-
nw, d.end, d.err = d.enc.decode(d.outbuf[0:], d.buf[0:nr])
392+
nw, d.end, err = d.enc.decode(d.outbuf[0:], d.buf[0:nr])
377393
d.out = d.outbuf[0:nw]
378394
n = copy(p, d.out)
379395
d.out = d.out[n:]
380396
} else {
381-
n, d.end, d.err = d.enc.decode(p, d.buf[0:nr])
397+
n, d.end, err = d.enc.decode(p, d.buf[0:nr])
382398
}
383399
d.nbuf -= nr
384400
for i := 0; i < d.nbuf; i++ {
385401
d.buf[i] = d.buf[i+nr]
386402
}
387403

388-
if d.err == nil {
404+
if err != nil && (d.err == nil || d.err == io.EOF) {
389405
d.err = err
390406
}
407+
408+
if len(d.out) > 0 {
409+
// We cannot return all the decoded bytes to the caller in this
410+
// invocation of Read, so we return a nil error to ensure that Read
411+
// will be called again. The error stored in d.err, if any, will be
412+
// returned with the last set of decoded bytes.
413+
return n, nil
414+
}
415+
391416
return n, d.err
392417
}
393418

@@ -407,7 +432,7 @@ func (r *newlineFilteringReader) Read(p []byte) (int, error) {
407432
offset++
408433
}
409434
}
410-
if offset > 0 {
435+
if err != nil || offset > 0 {
411436
return offset, err
412437
}
413438
// Previous buffer entirely whitespace, read again

src/encoding/base32/base32_test.go

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ package base32
66

77
import (
88
"bytes"
9+
"errors"
910
"io"
1011
"io/ioutil"
1112
"strings"
@@ -123,6 +124,160 @@ func TestDecoder(t *testing.T) {
123124
}
124125
}
125126

127+
type badReader struct {
128+
data []byte
129+
errs []error
130+
called int
131+
limit int
132+
}
133+
134+
// Populates p with data, returns a count of the bytes written and an
135+
// error. The error returned is taken from badReader.errs, with each
136+
// invocation of Read returning the next error in this slice, or io.EOF,
137+
// if all errors from the slice have already been returned. The
138+
// number of bytes returned is determined by the size of the input buffer
139+
// the test passes to decoder.Read and will be a multiple of 8, unless
140+
// badReader.limit is non zero.
141+
func (b *badReader) Read(p []byte) (int, error) {
142+
lim := len(p)
143+
if b.limit != 0 && b.limit < lim {
144+
lim = b.limit
145+
}
146+
if len(b.data) < lim {
147+
lim = len(b.data)
148+
}
149+
for i := range p[:lim] {
150+
p[i] = b.data[i]
151+
}
152+
b.data = b.data[lim:]
153+
err := io.EOF
154+
if b.called < len(b.errs) {
155+
err = b.errs[b.called]
156+
}
157+
b.called++
158+
return lim, err
159+
}
160+
161+
// TestIssue20044 tests that decoder.Read behaves correctly when the caller
162+
// supplied reader returns an error.
163+
func TestIssue20044(t *testing.T) {
164+
badErr := errors.New("bad reader error")
165+
testCases := []struct {
166+
r badReader
167+
res string
168+
err error
169+
dbuflen int
170+
}{
171+
// Check valid input data accompanied by an error is processed and the error is propagated.
172+
{r: badReader{data: []byte("MY======"), errs: []error{badErr}},
173+
res: "f", err: badErr},
174+
// Check a read error accompanied by input data consisting of newlines only is propagated.
175+
{r: badReader{data: []byte("\n\n\n\n\n\n\n\n"), errs: []error{badErr, nil}},
176+
res: "", err: badErr},
177+
// Reader will be called twice. The first time it will return 8 newline characters. The
178+
// second time valid base32 encoded data and an error. The data should be decoded
179+
// correctly and the error should be propagated.
180+
{r: badReader{data: []byte("\n\n\n\n\n\n\n\nMY======"), errs: []error{nil, badErr}},
181+
res: "f", err: badErr, dbuflen: 8},
182+
// Reader returns invalid input data (too short) and an error. Verify the reader
183+
// error is returned.
184+
{r: badReader{data: []byte("MY====="), errs: []error{badErr}},
185+
res: "", err: badErr},
186+
// Reader returns invalid input data (too short) but no error. Verify io.ErrUnexpectedEOF
187+
// is returned.
188+
{r: badReader{data: []byte("MY====="), errs: []error{nil}},
189+
res: "", err: io.ErrUnexpectedEOF},
190+
// Reader returns invalid input data and an error. Verify the reader and not the
191+
// decoder error is returned.
192+
{r: badReader{data: []byte("Ma======"), errs: []error{badErr}},
193+
res: "", err: badErr},
194+
// Reader returns valid data and io.EOF. Check data is decoded and io.EOF is propagated.
195+
{r: badReader{data: []byte("MZXW6YTB"), errs: []error{io.EOF}},
196+
res: "fooba", err: io.EOF},
197+
// Check errors are properly reported when decoder.Read is called multiple times.
198+
// decoder.Read will be called 8 times, badReader.Read will be called twice, returning
199+
// valid data both times but an error on the second call.
200+
{r: badReader{data: []byte("NRSWC43VOJSS4==="), errs: []error{nil, badErr}},
201+
res: "leasure.", err: badErr, dbuflen: 1},
202+
// Check io.EOF is properly reported when decoder.Read is called multiple times.
203+
// decoder.Read will be called 8 times, badReader.Read will be called twice, returning
204+
// valid data both times but io.EOF on the second call.
205+
{r: badReader{data: []byte("NRSWC43VOJSS4==="), errs: []error{nil, io.EOF}},
206+
res: "leasure.", err: io.EOF, dbuflen: 1},
207+
// The following two test cases check that errors are propagated correctly when more than
208+
// 8 bytes are read at a time.
209+
{r: badReader{data: []byte("NRSWC43VOJSS4==="), errs: []error{io.EOF}},
210+
res: "leasure.", err: io.EOF, dbuflen: 11},
211+
{r: badReader{data: []byte("NRSWC43VOJSS4==="), errs: []error{badErr}},
212+
res: "leasure.", err: badErr, dbuflen: 11},
213+
// Check that errors are correctly propagated when the reader returns valid bytes in
214+
// groups that are not divisible by 8. The first read will return 11 bytes and no
215+
// error. The second will return 7 and an error. The data should be decoded correctly
216+
// and the error should be propagated.
217+
{r: badReader{data: []byte("NRSWC43VOJSS4==="), errs: []error{nil, badErr}, limit: 11},
218+
res: "leasure.", err: badErr},
219+
}
220+
221+
for _, tc := range testCases {
222+
input := tc.r.data
223+
decoder := NewDecoder(StdEncoding, &tc.r)
224+
var dbuflen int
225+
if tc.dbuflen > 0 {
226+
dbuflen = tc.dbuflen
227+
} else {
228+
dbuflen = StdEncoding.DecodedLen(len(input))
229+
}
230+
dbuf := make([]byte, dbuflen)
231+
var err error
232+
var res []byte
233+
for err == nil {
234+
var n int
235+
n, err = decoder.Read(dbuf)
236+
if n > 0 {
237+
res = append(res, dbuf[:n]...)
238+
}
239+
}
240+
241+
testEqual(t, "Decoding of %q = %q, want %q", string(input), string(res), tc.res)
242+
testEqual(t, "Decoding of %q err = %v, expected %v", string(input), err, tc.err)
243+
}
244+
}
245+
246+
// TestDecoderError verifies decode errors are propagated when there are no read
247+
// errors.
248+
func TestDecoderError(t *testing.T) {
249+
for _, readErr := range []error{io.EOF, nil} {
250+
input := "MZXW6YTb"
251+
dbuf := make([]byte, StdEncoding.DecodedLen(len(input)))
252+
br := badReader{data: []byte(input), errs: []error{readErr}}
253+
decoder := NewDecoder(StdEncoding, &br)
254+
n, err := decoder.Read(dbuf)
255+
testEqual(t, "Read after EOF, n = %d, expected %d", n, 0)
256+
if _, ok := err.(CorruptInputError); !ok {
257+
t.Errorf("Corrupt input error expected. Found %T", err)
258+
}
259+
}
260+
}
261+
262+
// TestReaderEOF ensures decoder.Read behaves correctly when input data is
263+
// exhausted.
264+
func TestReaderEOF(t *testing.T) {
265+
for _, readErr := range []error{io.EOF, nil} {
266+
input := "MZXW6YTB"
267+
br := badReader{data: []byte(input), errs: []error{nil, readErr}}
268+
decoder := NewDecoder(StdEncoding, &br)
269+
dbuf := make([]byte, StdEncoding.DecodedLen(len(input)))
270+
n, err := decoder.Read(dbuf)
271+
testEqual(t, "Decoding of %q err = %v, expected %v", string(input), err, error(nil))
272+
n, err = decoder.Read(dbuf)
273+
testEqual(t, "Read after EOF, n = %d, expected %d", n, 0)
274+
testEqual(t, "Read after EOF, err = %v, expected %v", err, io.EOF)
275+
n, err = decoder.Read(dbuf)
276+
testEqual(t, "Read after EOF, n = %d, expected %d", n, 0)
277+
testEqual(t, "Read after EOF, err = %v, expected %v", err, io.EOF)
278+
}
279+
}
280+
126281
func TestDecoderBuffering(t *testing.T) {
127282
for bs := 1; bs <= 12; bs++ {
128283
decoder := NewDecoder(StdEncoding, strings.NewReader(bigtest.encoded))

0 commit comments

Comments
 (0)