aboutsummaryrefslogtreecommitdiff
path: root/libgo/go/encoding/json/scanner.go
diff options
context:
space:
mode:
Diffstat (limited to 'libgo/go/encoding/json/scanner.go')
-rw-r--r--libgo/go/encoding/json/scanner.go31
1 files changed, 19 insertions, 12 deletions
diff --git a/libgo/go/encoding/json/scanner.go b/libgo/go/encoding/json/scanner.go
index 552bd70..9dc1903 100644
--- a/libgo/go/encoding/json/scanner.go
+++ b/libgo/go/encoding/json/scanner.go
@@ -139,6 +139,10 @@ const (
parseArrayValue // parsing array value
)
+// This limits the max nesting depth to prevent stack overflow.
+// This is permitted by https://tools.ietf.org/html/rfc7159#section-9
+const maxNestingDepth = 10000
+
// reset prepares the scanner for use.
// It must be called before calling s.step.
func (s *scanner) reset() {
@@ -168,8 +172,13 @@ func (s *scanner) eof() int {
}
// pushParseState pushes a new parse state p onto the parse stack.
-func (s *scanner) pushParseState(p int) {
- s.parseState = append(s.parseState, p)
+// an error state is returned if maxNestingDepth was exceeded, otherwise successState is returned.
+func (s *scanner) pushParseState(c byte, newParseState int, successState int) int {
+ s.parseState = append(s.parseState, newParseState)
+ if len(s.parseState) <= maxNestingDepth {
+ return successState
+ }
+ return s.error(c, "exceeded max depth")
}
// popParseState pops a parse state (already obtained) off the stack
@@ -186,12 +195,12 @@ func (s *scanner) popParseState() {
}
func isSpace(c byte) bool {
- return c == ' ' || c == '\t' || c == '\r' || c == '\n'
+ return c <= ' ' && (c == ' ' || c == '\t' || c == '\r' || c == '\n')
}
// stateBeginValueOrEmpty is the state after reading `[`.
func stateBeginValueOrEmpty(s *scanner, c byte) int {
- if c <= ' ' && isSpace(c) {
+ if isSpace(c) {
return scanSkipSpace
}
if c == ']' {
@@ -202,18 +211,16 @@ func stateBeginValueOrEmpty(s *scanner, c byte) int {
// stateBeginValue is the state at the beginning of the input.
func stateBeginValue(s *scanner, c byte) int {
- if c <= ' ' && isSpace(c) {
+ if isSpace(c) {
return scanSkipSpace
}
switch c {
case '{':
s.step = stateBeginStringOrEmpty
- s.pushParseState(parseObjectKey)
- return scanBeginObject
+ return s.pushParseState(c, parseObjectKey, scanBeginObject)
case '[':
s.step = stateBeginValueOrEmpty
- s.pushParseState(parseArrayValue)
- return scanBeginArray
+ return s.pushParseState(c, parseArrayValue, scanBeginArray)
case '"':
s.step = stateInString
return scanBeginLiteral
@@ -242,7 +249,7 @@ func stateBeginValue(s *scanner, c byte) int {
// stateBeginStringOrEmpty is the state after reading `{`.
func stateBeginStringOrEmpty(s *scanner, c byte) int {
- if c <= ' ' && isSpace(c) {
+ if isSpace(c) {
return scanSkipSpace
}
if c == '}' {
@@ -255,7 +262,7 @@ func stateBeginStringOrEmpty(s *scanner, c byte) int {
// stateBeginString is the state after reading `{"key": value,`.
func stateBeginString(s *scanner, c byte) int {
- if c <= ' ' && isSpace(c) {
+ if isSpace(c) {
return scanSkipSpace
}
if c == '"' {
@@ -275,7 +282,7 @@ func stateEndValue(s *scanner, c byte) int {
s.endTop = true
return stateEndTop(s, c)
}
- if c <= ' ' && isSpace(c) {
+ if isSpace(c) {
s.step = stateEndValue
return scanSkipSpace
}