]> Cypherpunks.ru repositories - gostls13.git/commitdiff
fmt: fix handling of %% verb in Scanf
authorRob Pike <r@golang.org>
Thu, 24 Oct 2019 07:22:43 +0000 (18:22 +1100)
committerRob Pike <r@golang.org>
Fri, 25 Oct 2019 04:15:59 +0000 (04:15 +0000)
There were a couple of bugs, including not requiring a percent and
returning the wrong error for a bad format containing %%.

Both are addressed by fixing the first.

Fixes #34180.

Change-Id: If96c0c0258bcb95eec49871437d719cb9d399d9b
Reviewed-on: https://go-review.googlesource.com/c/go/+/202879
Run-TryBot: Emmanuel Odeke <emm.odeke@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Robert Griesemer <gri@golang.org>
src/fmt/scan.go
src/fmt/scan_test.go

index 0dab2c98f75ee72666bd829ac2f4d07d5ff923bd..8cab0180ee85f71fdf437ba7e6b322dac5cdac0d 100644 (file)
@@ -940,6 +940,15 @@ const (
        uintptrBits = 32 << (^uintptr(0) >> 63)
 )
 
+// scanPercent scans a literal percent character.
+func (s *ss) scanPercent() {
+       s.SkipSpace()
+       s.notEOF()
+       if !s.accept("%") {
+               s.errorString("missing literal %")
+       }
+}
+
 // scanOne scans a single value, deriving the scanner from the type of the argument.
 func (s *ss) scanOne(verb rune, arg interface{}) {
        s.buf = s.buf[:0]
@@ -1203,6 +1212,10 @@ func (s *ss) doScanf(format string, a []interface{}) (numProcessed int, err erro
                if c != 'c' {
                        s.SkipSpace()
                }
+               if c == '%' {
+                       s.scanPercent()
+                       continue // Do not consume an argument.
+               }
                s.argLimit = s.limit
                if f := s.count + s.maxWid; f < s.argLimit {
                        s.argLimit = f
index b14a6f5deb7aa863f9befcfa06964e6ba7124d74..1cc469ce3610c1411003ac255fc8c51005157449 100644 (file)
@@ -318,13 +318,15 @@ var scanfTests = []ScanfTest{
        {"%2s", "sssss", &xVal, Xs("ss")},
 
        // Fixed bugs
-       {"%d\n", "27\n", &intVal, 27},      // ok
-       {"%d\n", "28 \n", &intVal, 28},     // was: "unexpected newline"
-       {"%v", "0", &intVal, 0},            // was: "EOF"; 0 was taken as base prefix and not counted.
-       {"%v", "0", &uintVal, uint(0)},     // was: "EOF"; 0 was taken as base prefix and not counted.
-       {"%c", " ", &uintVal, uint(' ')},   // %c must accept a blank.
-       {"%c", "\t", &uintVal, uint('\t')}, // %c must accept any space.
-       {"%c", "\n", &uintVal, uint('\n')}, // %c must accept any space.
+       {"%d\n", "27\n", &intVal, 27},         // ok
+       {"%d\n", "28 \n", &intVal, 28},        // was: "unexpected newline"
+       {"%v", "0", &intVal, 0},               // was: "EOF"; 0 was taken as base prefix and not counted.
+       {"%v", "0", &uintVal, uint(0)},        // was: "EOF"; 0 was taken as base prefix and not counted.
+       {"%c", " ", &uintVal, uint(' ')},      // %c must accept a blank.
+       {"%c", "\t", &uintVal, uint('\t')},    // %c must accept any space.
+       {"%c", "\n", &uintVal, uint('\n')},    // %c must accept any space.
+       {"%d%%", "23%\n", &uintVal, uint(23)}, // %% matches literal %.
+       {"%%%d", "%23\n", &uintVal, uint(23)}, // %% matches literal %.
 
        // space handling
        {"%d", "27", &intVal, 27},
@@ -467,6 +469,9 @@ var multiTests = []ScanfMultiTest{
        {"X%d", "10X", args(&intVal), nil, "input does not match format"},
        {"%d%", "42%", args(&intVal), args(42), "missing verb: % at end of format string"},
        {"%d% ", "42%", args(&intVal), args(42), "too few operands for format '% '"}, // Slightly odd error, but correct.
+       {"%%%d", "xxx 42", args(&intVal), args(42), "missing literal %"},
+       {"%%%d", "x42", args(&intVal), args(42), "missing literal %"},
+       {"%%%d", "42", args(&intVal), args(42), "missing literal %"},
 
        // Bad UTF-8: should see every byte.
        {"%c%c%c", "\xc2X\xc2", args(&r1, &r2, &r3), args(utf8.RuneError, 'X', utf8.RuneError), ""},