fmt: fix bug in scanning of hex strings
Couldn't handle a hex string terminated by anything
other than spaces. Easy to fix.
Fixes #9124.
Change-Id: I18f89a0bd99a105c9110e1ede641873bf9daf3af
Reviewed-on: https://go-review.googlesource.com/1538
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
diff --git a/src/fmt/fmt_test.go b/src/fmt/fmt_test.go
index ff5fa79..c933e84 100644
--- a/src/fmt/fmt_test.go
+++ b/src/fmt/fmt_test.go
@@ -1231,7 +1231,7 @@
type B struct{}
var a *A = nil
var b B = B{}
- got := Sprintf("%s %s %s %s %s", nil, a, nil, b, nil)
+ got := Sprintf("%s %s %s %s %s", nil, a, nil, b, nil) // go vet should complain about this line.
const expect = "%!s(<nil>) %!s(*fmt_test.A=<nil>) %!s(<nil>) {} %!s(<nil>)"
if got != expect {
t.Errorf("expected:\n\t%q\ngot:\n\t%q", expect, got)
diff --git a/src/fmt/scan.go b/src/fmt/scan.go
index d7befea..93cd553 100644
--- a/src/fmt/scan.go
+++ b/src/fmt/scan.go
@@ -875,34 +875,40 @@
return ""
}
-// hexDigit returns the value of the hexadecimal digit
-func (s *ss) hexDigit(d rune) int {
+// hexDigit returns the value of the hexadecimal digit.
+func hexDigit(d rune) (int, bool) {
digit := int(d)
switch digit {
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
- return digit - '0'
+ return digit - '0', true
case 'a', 'b', 'c', 'd', 'e', 'f':
- return 10 + digit - 'a'
+ return 10 + digit - 'a', true
case 'A', 'B', 'C', 'D', 'E', 'F':
- return 10 + digit - 'A'
+ return 10 + digit - 'A', true
}
- s.errorString("illegal hex digit")
- return 0
+ return -1, false
}
// hexByte returns the next hex-encoded (two-character) byte from the input.
-// There must be either two hexadecimal digits or a space character in the input.
+// It returns ok==false if the next bytes in the input do not encode a hex byte.
+// If the first byte is hex and the second is not, processing stops.
func (s *ss) hexByte() (b byte, ok bool) {
rune1 := s.getRune()
if rune1 == eof {
- return
- }
- if isSpace(rune1) {
s.UnreadRune()
return
}
- rune2 := s.mustReadRune()
- return byte(s.hexDigit(rune1)<<4 | s.hexDigit(rune2)), true
+ value1, ok := hexDigit(rune1)
+ if !ok {
+ s.UnreadRune()
+ return
+ }
+ value2, ok := hexDigit(s.mustReadRune())
+ if !ok {
+ s.errorString("illegal hex digit")
+ return
+ }
+ return byte(value1<<4 | value2), true
}
// hexString returns the space-delimited hexpair-encoded string.
diff --git a/src/fmt/scan_test.go b/src/fmt/scan_test.go
index 541e12d..a932831 100644
--- a/src/fmt/scan_test.go
+++ b/src/fmt/scan_test.go
@@ -864,7 +864,7 @@
t.Fatal(err)
}
if n != 3 {
- t.Fatalf("expected 3 items consumed, got %d")
+ t.Fatalf("expected 3 items consumed, got %d", n)
}
if a.rune != '1' || b.rune != '2' || c.rune != '➂' {
t.Errorf("bad scan rune: %q %q %q should be '1' '2' '➂'", a.rune, b.rune, c.rune)
@@ -990,3 +990,57 @@
b.StopTimer()
}
}
+
+// Issue 9124.
+// %x on bytes couldn't handle non-space bytes terminating the scan.
+func TestHexBytes(t *testing.T) {
+ var a, b []byte
+ n, err := Sscanf("00010203", "%x", &a)
+ if n != 1 || err != nil {
+ t.Errorf("simple: got count, err = %d, %v; expected 1, nil", n, err)
+ }
+ check := func(msg string, x []byte) {
+ if len(x) != 4 {
+ t.Errorf("%s: bad length %d", msg, len(x))
+ }
+ for i, b := range x {
+ if int(b) != i {
+ t.Errorf("%s: bad x[%d] = %x", msg, i, x[i])
+ }
+ }
+ }
+ check("simple", a)
+ a = nil
+
+ n, err = Sscanf("00010203 00010203", "%x %x", &a, &b)
+ if n != 2 || err != nil {
+ t.Errorf("simple pair: got count, err = %d, %v; expected 2, nil", n, err)
+ }
+ check("simple pair a", a)
+ check("simple pair b", b)
+ a = nil
+ b = nil
+
+ n, err = Sscanf("00010203:", "%x", &a)
+ if n != 1 || err != nil {
+ t.Errorf("colon: got count, err = %d, %v; expected 1, nil", n, err)
+ }
+ check("colon", a)
+ a = nil
+
+ n, err = Sscanf("00010203:00010203", "%x:%x", &a, &b)
+ if n != 2 || err != nil {
+ t.Errorf("colon pair: got count, err = %d, %v; expected 2, nil", n, err)
+ }
+ check("colon pair a", a)
+ check("colon pair b", b)
+ a = nil
+ b = nil
+
+ // This one fails because there is a hex byte after the data,
+ // that is, an odd number of hex input bytes.
+ n, err = Sscanf("000102034:", "%x", &a)
+ if n != 0 || err == nil {
+ t.Errorf("odd count: got count, err = %d, %v; expected 0, error", n, err)
+ }
+}