]> Cypherpunks repositories - gostls13.git/commitdiff
bufio.Scan: don't stop after Read returns 0, nil
authorRob Pike <r@golang.org>
Fri, 19 Apr 2013 00:37:21 +0000 (17:37 -0700)
committerRob Pike <r@golang.org>
Fri, 19 Apr 2013 00:37:21 +0000 (17:37 -0700)
But stop eventually if the reader misbehaves.

R=golang-dev, bradfitz
CC=golang-dev
https://golang.org/cl/8757045

src/pkg/bufio/scan.go
src/pkg/bufio/scan_test.go

index cebe92d331e6af1af37fb5d13df052d69d9ea0da..2e1a2e99973e23b0e617da127f4c50bd481e08c6 100644 (file)
@@ -103,8 +103,7 @@ func (s *Scanner) Text() string {
 
 // Scan advances the Scanner to the next token, which will then be
 // available through the Bytes or Text method. It returns false when the
-// scan stops, either by reaching the end of the input, a zero-length
-// read from the input, or an error.
+// scan stops, either by reaching the end of the input or an error.
 // After Scan returns false, the Err method will return any error that
 // occurred during scanning, except that if it was io.EOF, Err
 // will return nil.
@@ -159,15 +158,25 @@ func (s *Scanner) Scan() bool {
                        s.start = 0
                        continue
                }
-               // Finally we can read some input.
-               n, err := s.r.Read(s.buf[s.end:len(s.buf)])
-               if err != nil {
-                       s.setErr(err)
-               }
-               if n == 0 { // Don't loop forever if Reader doesn't deliver EOF.
-                       s.setErr(io.EOF)
+               // Finally we can read some input. Make sure we don't get stuck with
+               // a misbehaving Reader. Officially we don't need to do this, but let's
+               // be extra careful: Scanner is for safe, simple jobs.
+               for loop := 0; ; {
+                       n, err := s.r.Read(s.buf[s.end:len(s.buf)])
+                       s.end += n
+                       if err != nil {
+                               s.setErr(err)
+                               break
+                       }
+                       if n > 0 {
+                               break
+                       }
+                       loop++
+                       if loop > 100 {
+                               s.setErr(io.ErrNoProgress)
+                               break
+                       }
                }
-               s.end += n
        }
 }
 
index 1b112f46dabad8bd487621c8e635f3d572984e47..c1483b2685855da7b49c560e95ccc73549356c04 100644 (file)
@@ -386,3 +386,21 @@ func TestNonEOFWithEmptyRead(t *testing.T) {
                t.Errorf("unexpected error: %v", err)
        }
 }
+
+// Test that Scan finishes if we have endless empty reads.
+type endlessZeros struct{}
+
+func (endlessZeros) Read(p []byte) (int, error) {
+       return 0, nil
+}
+
+func TestBadReader(t *testing.T) {
+       scanner := NewScanner(endlessZeros{})
+       for scanner.Scan() {
+               t.Fatal("read should fail")
+       }
+       err := scanner.Err()
+       if err != io.ErrNoProgress {
+               t.Errorf("unexpected error: %v", err)
+       }
+}