Commit b38fba21 authored by Robert Griesemer's avatar Robert Griesemer

bufio: fix potential endless loop in ReadByte

Fixes #7745.

LGTM=bradfitz, r
R=r, bradfitz
CC=golang-codereviews
https://golang.org/cl/86220044
parent 8bd9242f
...@@ -88,7 +88,8 @@ func (b *Reader) fill() { ...@@ -88,7 +88,8 @@ func (b *Reader) fill() {
b.r = 0 b.r = 0
} }
// Read new data. // Read new data: try a limited number of times.
for i := maxConsecutiveEmptyReads; i > 0; i-- {
n, err := b.rd.Read(b.buf[b.w:]) n, err := b.rd.Read(b.buf[b.w:])
if n < 0 { if n < 0 {
panic(errNegativeRead) panic(errNegativeRead)
...@@ -96,7 +97,13 @@ func (b *Reader) fill() { ...@@ -96,7 +97,13 @@ func (b *Reader) fill() {
b.w += n b.w += n
if err != nil { if err != nil {
b.err = err b.err = err
return
}
if n > 0 {
return
} }
}
b.err = io.ErrNoProgress
} }
func (b *Reader) readErr() error { func (b *Reader) readErr() error {
...@@ -151,6 +158,9 @@ func (b *Reader) Read(p []byte) (n int, err error) { ...@@ -151,6 +158,9 @@ func (b *Reader) Read(p []byte) (n int, err error) {
// Large read, empty buffer. // Large read, empty buffer.
// Read directly into p to avoid copy. // Read directly into p to avoid copy.
n, b.err = b.rd.Read(p) n, b.err = b.rd.Read(p)
if n < 0 {
panic(errNegativeRead)
}
if n > 0 { if n > 0 {
b.lastByte = int(p[n-1]) b.lastByte = int(p[n-1])
b.lastRuneSize = -1 b.lastRuneSize = -1
......
...@@ -14,6 +14,7 @@ import ( ...@@ -14,6 +14,7 @@ import (
"strings" "strings"
"testing" "testing"
"testing/iotest" "testing/iotest"
"time"
"unicode/utf8" "unicode/utf8"
) )
...@@ -174,6 +175,34 @@ func TestReader(t *testing.T) { ...@@ -174,6 +175,34 @@ func TestReader(t *testing.T) {
} }
} }
type zeroReader struct{}
func (zeroReader) Read(p []byte) (int, error) {
return 0, nil
}
func TestZeroReader(t *testing.T) {
var z zeroReader
r := NewReader(z)
c := make(chan error)
go func() {
_, err := r.ReadByte()
c <- err
}()
select {
case err := <-c:
if err == nil {
t.Error("error expected")
} else if err != io.ErrNoProgress {
t.Error("unexpected error:", err)
}
case <-time.After(time.Second):
t.Error("test timed out (endless loop in ReadByte?)")
}
}
// A StringReader delivers its data one string segment at a time via Read. // A StringReader delivers its data one string segment at a time via Read.
type StringReader struct { type StringReader struct {
data []string data []string
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment