diff options
| author | Erik Dubbelboer <erik@dubbelboer.com> | 2015-07-15 16:12:05 +0200 |
|---|---|---|
| committer | Russ Cox <rsc@golang.org> | 2015-11-25 16:18:36 +0000 |
| commit | c4be790c0e20bfa4def3103392f404de201b3487 (patch) | |
| tree | 6fa960e0776631ddb57ffad75579f503478def35 /src/encoding/json/decode.go | |
| parent | 64cc5fd0b3ad20c6e7e8b875317629df8207d9ba (diff) | |
| download | go-c4be790c0e20bfa4def3103392f404de201b3487.tar.xz | |
encoding/json: check if Number is valid
json.Number is a special case which didn't have any checks and could result in invalid JSON.
Fixes #10281
Change-Id: Ie3e726e4d6bf6a6aba535d36f6107013ceac913a
Reviewed-on: https://go-review.googlesource.com/12250
Reviewed-by: Russ Cox <rsc@golang.org>
Diffstat (limited to 'src/encoding/json/decode.go')
| -rw-r--r-- | src/encoding/json/decode.go | 121 |
1 files changed, 121 insertions, 0 deletions
diff --git a/src/encoding/json/decode.go b/src/encoding/json/decode.go index bd939b4258..ef08b0c274 100644 --- a/src/encoding/json/decode.go +++ b/src/encoding/json/decode.go @@ -174,6 +174,124 @@ func (n Number) Int64() (int64, error) { return strconv.ParseInt(string(n), 10, 64) } +// IsValid returns if the number is a valid JSON number literal. +func (n Number) IsValid() bool { + // This function implements the JSON numbers grammar. + // See https://tools.ietf.org/html/rfc7159#section-6 + // and http://json.org/number.gif + + l := len(n) + if l == 0 { + return false + } + + i := 0 + c := n[i] + i++ + + // Optional - + if c == '-' { + if i == l { + return false + } + + c = n[i] + i++ + } + + // 1-9 + if c >= '1' && c <= '9' { + // Eat digits. + for ; i < l; i++ { + c = n[i] + if c < '0' || c > '9' { + break + } + } + i++ + } else if c != '0' { + // If it's not 0 or 1-9 it's invalid. + return false + } else { + if i == l { + // Just 0 + return true + } + + // Skip the 0 + c = n[i] + i++ + } + + // . followed by 1 or more digits. + if c == '.' { + if i == l { + // Just 1. is invalid. + return false + } + + // . needs to be followed by at least one digit. + c = n[i] + i++ + if c < '0' || c > '9' { + return false + } + + // Eat digits. + for ; i < l; i++ { + c = n[i] + if c < '0' || c > '9' { + break + } + } + i++ + } + + // e or E followed by an optional - or + and + // 1 or more digits. + if c == 'e' || c == 'E' { + if i == l { + // Just 1e is invalid. + return false + } + + c = n[i] + i++ + + // Optional - or + + if c == '-' || c == '+' { + if i == l { + // Just 1e+ is invalid. + return false + } + + c = n[i] + i++ + } + + // Need to have a digit. + if c < '0' || c > '9' { + return false + } + + // Eat digits. + for ; i < l; i++ { + c = n[i] + if c < '0' || c > '9' { + break + } + } + i++ + } + + // Make sure we are at the end. + if i <= l { + return false + } + + return true +} + // decodeState represents the state while decoding a JSON value. type decodeState struct { data []byte @@ -781,6 +899,9 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool default: if v.Kind() == reflect.String && v.Type() == numberType { v.SetString(s) + if !Number(s).IsValid() { + d.error(fmt.Errorf("json: invalid number literal, trying to unmarshal %q into Number", item)) + } break } if fromQuoted { |
