bufio: fix UnreadSlice followed by UnreadRune
Also, fix a write check in writeBuf and make some bounds checks simpler.
LGTM=gri
R=golang-codereviews, adg, gri, r, minux
CC=golang-codereviews
https://golang.org/cl/113060043
diff --git a/src/pkg/bufio/bufio.go b/src/pkg/bufio/bufio.go
index 61ef261..d3c68fe 100644
--- a/src/pkg/bufio/bufio.go
+++ b/src/pkg/bufio/bufio.go
@@ -30,8 +30,8 @@
// Reader implements buffering for an io.Reader object.
type Reader struct {
buf []byte
- rd io.Reader
- r, w int
+ rd io.Reader // reader provided by the client
+ r, w int // buf read and write positions
err error
lastByte int
lastRuneSize int
@@ -131,18 +131,17 @@
for b.w-b.r < n && b.err == nil {
b.fill() // b.w-b.r < len(b.buf) => buffer is not full
}
- m := b.w - b.r
- if m > n {
- m = n
- }
+
var err error
- if m < n {
+ if avail := b.w - b.r; avail < n {
+ // not enough data in buffer
+ n = avail
err = b.readErr()
if err == nil {
err = ErrBufferFull
}
}
- return b.buf[b.r : b.r+m], err
+ return b.buf[b.r : b.r+n], err
}
// Read reads data into p.
@@ -173,15 +172,13 @@
return n, b.readErr()
}
b.fill() // buffer is empty
- if b.w == b.r {
+ if b.r == b.w {
return 0, b.readErr()
}
}
- if n > b.w-b.r {
- n = b.w - b.r
- }
- copy(p[0:n], b.buf[b.r:])
+ // copy as much as we can
+ n = copy(p, b.buf[b.r:b.w])
b.r += n
b.lastByte = int(b.buf[b.r-1])
b.lastRuneSize = -1
@@ -288,7 +285,7 @@
}
// Buffer full?
- if n := b.Buffered(); n >= len(b.buf) {
+ if b.Buffered() >= len(b.buf) {
b.r = b.w
line = b.buf
err = ErrBufferFull
@@ -301,6 +298,7 @@
// Handle last byte, if any.
if i := len(line) - 1; i >= 0 {
b.lastByte = int(line[i])
+ b.lastRuneSize = -1
}
return
@@ -458,11 +456,13 @@
return n, b.readErr()
}
+var errNegativeWrite = errors.New("bufio: writer returned negative count from Write")
+
// writeBuf writes the Reader's buffer to the writer.
func (b *Reader) writeBuf(w io.Writer) (int64, error) {
n, err := w.Write(b.buf[b.r:b.w])
- if n < b.r-b.w {
- panic(errors.New("bufio: writer did not write all data"))
+ if n < 0 {
+ panic(errNegativeWrite)
}
b.r += n
return int64(n), err
diff --git a/src/pkg/bufio/bufio_test.go b/src/pkg/bufio/bufio_test.go
index be43a80..4f3bc10 100644
--- a/src/pkg/bufio/bufio_test.go
+++ b/src/pkg/bufio/bufio_test.go
@@ -463,6 +463,18 @@
if r.UnreadRune() == nil {
t.Error("expected error after UnreadByte (3)")
}
+ // Test error after ReadSlice.
+ _, _, err = r.ReadRune() // reset state
+ if err != nil {
+ t.Error("unexpected error on ReadRune (4):", err)
+ }
+ _, err = r.ReadSlice(0)
+ if err != io.EOF {
+ t.Error("unexpected error on ReadSlice (4):", err)
+ }
+ if r.UnreadRune() == nil {
+ t.Error("expected error after ReadSlice (4)")
+ }
}
func TestUnreadRuneAtEOF(t *testing.T) {
diff --git a/src/pkg/bufio/scan.go b/src/pkg/bufio/scan.go
index 97ae109..c5714f3 100644
--- a/src/pkg/bufio/scan.go
+++ b/src/pkg/bufio/scan.go
@@ -64,8 +64,9 @@
)
const (
- // Maximum size used to buffer a token. The actual maximum token size
- // may be smaller as the buffer may need to include, for instance, a newline.
+ // MaxScanTokenSize is the maximum size used to buffer a token.
+ // The actual maximum token size may be smaller as the buffer
+ // may need to include, for instance, a newline.
MaxScanTokenSize = 64 * 1024
)