opRead // Any other read operation.
)
-// ErrTooLarge is returned if there is too much data to fit in a buffer.
+// ErrTooLarge is passed to panic if memory cannot be allocated to store data in a buffer.
var ErrTooLarge = errors.New("bytes.Buffer: too large")
// Bytes returns a slice of the contents of the unread portion of the buffer;
// grow grows the buffer to guarantee space for n more bytes.
// It returns the index where bytes should be written.
-// If the buffer can't grow, it returns -1, which will
-// become ErrTooLarge in the caller.
+// If the buffer can't grow it will panic with ErrTooLarge.
func (b *Buffer) grow(n int) int {
m := b.Len()
// If buffer is empty, reset to recover space.
} else {
// not enough space anywhere
buf = makeSlice(2*cap(b.buf) + n)
- if buf == nil {
- return -1
- }
copy(buf, b.buf[b.off:])
}
b.buf = buf
// Write appends the contents of p to the buffer. The return
// value n is the length of p; err is always nil.
+// If the buffer becomes too large, Write will panic with
+// ErrTooLarge.
func (b *Buffer) Write(p []byte) (n int, err error) {
b.lastRead = opInvalid
m := b.grow(len(p))
// not enough space using beginning of buffer;
// double buffer capacity
newBuf = makeSlice(2*cap(b.buf) + MinRead)
- if newBuf == nil {
- return n, ErrTooLarge
- }
}
copy(newBuf, b.buf[b.off:])
b.buf = newBuf[:len(b.buf)-b.off]
return n, nil // err is EOF, so return nil explicitly
}
-// makeSlice allocates a slice of size n, returning nil if the slice cannot be allocated.
+// makeSlice allocates a slice of size n. If the allocation fails, it panics
+// with ErrTooLarge.
func makeSlice(n int) []byte {
- if n < 0 {
- return nil
- }
- // Catch out of memory panics.
+ // If the make fails, give a known error.
defer func() {
- recover()
+ if recover() != nil {
+ panic(ErrTooLarge)
+ }
}()
return make([]byte, n)
}
if testing.Short() {
return
}
+ // We expect a panic.
+ defer func() {
+ if err, ok := recover().(error); ok && err == ErrTooLarge {
+ return
+ } else {
+ t.Error(`expected "too large" error; got`, err)
+ }
+ }()
b := new(Buffer)
big := make([]byte, 500e6)
for i := 0; i < 1000; i++ {
- if _, err := b.Write(big); err != nil {
- // Got error as expected. Stop
- return
- }
+ b.Write(big)
}
- t.Error("error expected")
+ t.Error("panic expected")
}
// readAll reads from r until an error or EOF and returns the data it read
// from the internal buffer allocated with a specified capacity.
-func readAll(r io.Reader, capacity int64) ([]byte, error) {
+func readAll(r io.Reader, capacity int64) (b []byte, err error) {
buf := bytes.NewBuffer(make([]byte, 0, capacity))
- _, err := buf.ReadFrom(r)
+ // If the buffer overflows, we will get bytes.ErrTooLarge.
+ // Return that as an error. Any other panic remains.
+ defer func() {
+ e := recover()
+ if e == nil {
+ return
+ }
+ if panicErr, ok := e.(error); ok && panicErr == bytes.ErrTooLarge {
+ err = panicErr
+ } else {
+ panic(e)
+ }
+ }()
+ _, err = buf.ReadFrom(r)
return buf.Bytes(), err
}