1
0
mirror of https://github.com/golang/go synced 2024-11-25 15:17:58 -07:00

io: prevent ReadAtLeast spinloop if min > len(buf)

R=r, heresy.mc
CC=golang-dev
https://golang.org/cl/2017042
This commit is contained in:
Andrew Gerrand 2010-08-23 12:04:15 +10:00
parent d125faeed0
commit 4642708984
2 changed files with 48 additions and 2 deletions

View File

@ -19,6 +19,9 @@ type Error struct {
// but failed to return an explicit error. // but failed to return an explicit error.
var ErrShortWrite os.Error = &Error{"short write"} var ErrShortWrite os.Error = &Error{"short write"}
// ErrShortBuffer means that a read required a longer buffer than was provided.
var ErrShortBuffer os.Error = &Error{"short buffer"}
// ErrUnexpectedEOF means that os.EOF was encountered in the // ErrUnexpectedEOF means that os.EOF was encountered in the
// middle of reading a fixed-size block or data structure. // middle of reading a fixed-size block or data structure.
var ErrUnexpectedEOF os.Error = &Error{"unexpected EOF"} var ErrUnexpectedEOF os.Error = &Error{"unexpected EOF"}
@ -165,8 +168,11 @@ func WriteString(w Writer, s string) (n int, err os.Error) {
// The error is os.EOF only if no bytes were read. // The error is os.EOF only if no bytes were read.
// If an EOF happens after reading fewer than min bytes, // If an EOF happens after reading fewer than min bytes,
// ReadAtLeast returns ErrUnexpectedEOF. // ReadAtLeast returns ErrUnexpectedEOF.
// If min is greater than the length of buf, ReadAtLeast returns ErrShortBuffer.
func ReadAtLeast(r Reader, buf []byte, min int) (n int, err os.Error) { func ReadAtLeast(r Reader, buf []byte, min int) (n int, err os.Error) {
n = 0 if len(buf) < min {
return 0, ErrShortBuffer
}
for n < min { for n < min {
nn, e := r.Read(buf[n:]) nn, e := r.Read(buf[n:])
if nn > 0 { if nn > 0 {
@ -179,7 +185,7 @@ func ReadAtLeast(r Reader, buf []byte, min int) (n int, err os.Error) {
return n, e return n, e
} }
} }
return n, nil return
} }
// ReadFull reads exactly len(buf) bytes from r into buf. // ReadFull reads exactly len(buf) bytes from r into buf.

View File

@ -7,6 +7,7 @@ package io_test
import ( import (
"bytes" "bytes"
. "io" . "io"
"os"
"testing" "testing"
) )
@ -78,3 +79,42 @@ func TestCopynWriteTo(t *testing.T) {
t.Errorf("Copyn did not work properly") t.Errorf("Copyn did not work properly")
} }
} }
func TestReadAtLeast(t *testing.T) {
var rb bytes.Buffer
rb.Write([]byte("0123"))
buf := make([]byte, 2)
n, err := ReadAtLeast(&rb, buf, 2)
if err != nil {
t.Error(err)
}
n, err = ReadAtLeast(&rb, buf, 4)
if err != ErrShortBuffer {
t.Errorf("expected ErrShortBuffer got %v", err)
}
if n != 0 {
t.Errorf("expected to have read 0 bytes, got %v", n)
}
n, err = ReadAtLeast(&rb, buf, 1)
if err != nil {
t.Error(err)
}
if n != 2 {
t.Errorf("expected to have read 2 bytes, got %v", n)
}
n, err = ReadAtLeast(&rb, buf, 2)
if err != os.EOF {
t.Errorf("expected EOF, got %v", err)
}
if n != 0 {
t.Errorf("expected to have read 0 bytes, got %v", n)
}
rb.Write([]byte("4"))
n, err = ReadAtLeast(&rb, buf, 2)
if err != ErrUnexpectedEOF {
t.Errorf("expected ErrUnexpectedEOF, got %v", err)
}
if n != 1 {
t.Errorf("expected to have read 1 bytes, got %v", n)
}
}