mirror of
https://github.com/golang/go
synced 2024-11-16 19:34:48 -07:00
bufio: permit r.Reset(r) without infinite recursion
This can happen in reasonable code because NewReader(r) can return r, if r is already a Reader. Similarly for Writer. Fixes #58423 Change-Id: Iff9d9265410bee68fbaeb7175369847bd737eb2c Reviewed-on: https://go-review.googlesource.com/c/go/+/466815 Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org> TryBot-Result: Gopher Robot <gobot@golang.org> Auto-Submit: Ian Lance Taylor <iant@google.com> Reviewed-by: Bryan Mills <bcmills@google.com> Run-TryBot: Ian Lance Taylor <iant@google.com> Reviewed-by: Ian Lance Taylor <iant@google.com> Run-TryBot: Ian Lance Taylor <iant@golang.org>
This commit is contained in:
parent
a7fe9ada10
commit
851f6fd614
@ -70,7 +70,14 @@ func (b *Reader) Size() int { return len(b.buf) }
|
|||||||
// the buffered reader to read from r.
|
// the buffered reader to read from r.
|
||||||
// Calling Reset on the zero value of Reader initializes the internal buffer
|
// Calling Reset on the zero value of Reader initializes the internal buffer
|
||||||
// to the default size.
|
// to the default size.
|
||||||
|
// Calling b.Reset(b) (that is, resetting a Reader to itself) does nothing.
|
||||||
func (b *Reader) Reset(r io.Reader) {
|
func (b *Reader) Reset(r io.Reader) {
|
||||||
|
// If a Reader r is passed to NewReader, NewReader will return r.
|
||||||
|
// Different layers of code may do that, and then later pass r
|
||||||
|
// to Reset. Avoid infinite recursion in that case.
|
||||||
|
if b == r {
|
||||||
|
return
|
||||||
|
}
|
||||||
if b.buf == nil {
|
if b.buf == nil {
|
||||||
b.buf = make([]byte, defaultBufSize)
|
b.buf = make([]byte, defaultBufSize)
|
||||||
}
|
}
|
||||||
@ -608,7 +615,14 @@ func (b *Writer) Size() int { return len(b.buf) }
|
|||||||
// resets b to write its output to w.
|
// resets b to write its output to w.
|
||||||
// Calling Reset on the zero value of Writer initializes the internal buffer
|
// Calling Reset on the zero value of Writer initializes the internal buffer
|
||||||
// to the default size.
|
// to the default size.
|
||||||
|
// Calling w.Reset(w) (that is, resetting a Writer to itself) does nothing.
|
||||||
func (b *Writer) Reset(w io.Writer) {
|
func (b *Writer) Reset(w io.Writer) {
|
||||||
|
// If a Writer w is passed to NewWriter, NewWriter will return w.
|
||||||
|
// Different layers of code may do that, and then later pass w
|
||||||
|
// to Reset. Avoid infinite recursion in that case.
|
||||||
|
if b == w {
|
||||||
|
return
|
||||||
|
}
|
||||||
if b.buf == nil {
|
if b.buf == nil {
|
||||||
b.buf = make([]byte, defaultBufSize)
|
b.buf = make([]byte, defaultBufSize)
|
||||||
}
|
}
|
||||||
|
@ -1482,6 +1482,17 @@ func TestReadZero(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestReaderReset(t *testing.T) {
|
func TestReaderReset(t *testing.T) {
|
||||||
|
checkAll := func(r *Reader, want string) {
|
||||||
|
t.Helper()
|
||||||
|
all, err := io.ReadAll(r)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if string(all) != want {
|
||||||
|
t.Errorf("ReadAll returned %q, want %q", all, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
r := NewReader(strings.NewReader("foo foo"))
|
r := NewReader(strings.NewReader("foo foo"))
|
||||||
buf := make([]byte, 3)
|
buf := make([]byte, 3)
|
||||||
r.Read(buf)
|
r.Read(buf)
|
||||||
@ -1490,27 +1501,23 @@ func TestReaderReset(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
r.Reset(strings.NewReader("bar bar"))
|
r.Reset(strings.NewReader("bar bar"))
|
||||||
all, err := io.ReadAll(r)
|
checkAll(r, "bar bar")
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
if string(all) != "bar bar" {
|
|
||||||
t.Errorf("ReadAll = %q; want bar bar", all)
|
|
||||||
}
|
|
||||||
|
|
||||||
*r = Reader{} // zero out the Reader
|
*r = Reader{} // zero out the Reader
|
||||||
r.Reset(strings.NewReader("bar bar"))
|
r.Reset(strings.NewReader("bar bar"))
|
||||||
all, err = io.ReadAll(r)
|
checkAll(r, "bar bar")
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
// Wrap a reader and then Reset to that reader.
|
||||||
}
|
r.Reset(strings.NewReader("recur"))
|
||||||
if string(all) != "bar bar" {
|
r2 := NewReader(r)
|
||||||
t.Errorf("ReadAll = %q; want bar bar", all)
|
checkAll(r2, "recur")
|
||||||
}
|
r.Reset(strings.NewReader("recur2"))
|
||||||
|
r2.Reset(r)
|
||||||
|
checkAll(r2, "recur2")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestWriterReset(t *testing.T) {
|
func TestWriterReset(t *testing.T) {
|
||||||
var buf1, buf2, buf3 strings.Builder
|
var buf1, buf2, buf3, buf4, buf5 strings.Builder
|
||||||
w := NewWriter(&buf1)
|
w := NewWriter(&buf1)
|
||||||
w.WriteString("foo")
|
w.WriteString("foo")
|
||||||
|
|
||||||
@ -1534,6 +1541,22 @@ func TestWriterReset(t *testing.T) {
|
|||||||
if buf3.String() != "bar" {
|
if buf3.String() != "bar" {
|
||||||
t.Errorf("buf3 = %q; want bar", buf3.String())
|
t.Errorf("buf3 = %q; want bar", buf3.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Wrap a writer and then Reset to that writer.
|
||||||
|
w.Reset(&buf4)
|
||||||
|
w2 := NewWriter(w)
|
||||||
|
w2.WriteString("recur")
|
||||||
|
w2.Flush()
|
||||||
|
if buf4.String() != "recur" {
|
||||||
|
t.Errorf("buf4 = %q, want %q", buf4.String(), "recur")
|
||||||
|
}
|
||||||
|
w.Reset(&buf5)
|
||||||
|
w2.Reset(w)
|
||||||
|
w2.WriteString("recur2")
|
||||||
|
w2.Flush()
|
||||||
|
if buf5.String() != "recur2" {
|
||||||
|
t.Errorf("buf5 = %q, want %q", buf5.String(), "recur2")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestReaderDiscard(t *testing.T) {
|
func TestReaderDiscard(t *testing.T) {
|
||||||
|
Loading…
Reference in New Issue
Block a user