aboutsummaryrefslogtreecommitdiff
path: root/src/encoding/json/decode.go
diff options
context:
space:
mode:
authorErik Dubbelboer <erik@dubbelboer.com>2015-07-15 16:12:05 +0200
committerRuss Cox <rsc@golang.org>2015-11-25 16:18:36 +0000
commitc4be790c0e20bfa4def3103392f404de201b3487 (patch)
tree6fa960e0776631ddb57ffad75579f503478def35 /src/encoding/json/decode.go
parent64cc5fd0b3ad20c6e7e8b875317629df8207d9ba (diff)
downloadgo-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.go121
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 {