@@ -55,8 +55,21 @@ type Parser struct {
5555 left []byte
5656 nodes []Node
5757 err error
58+
59+ // nesting is the current depth of nested arrays and inline tables being
60+ // parsed. It guards parseVal/parseValArray/parseInlineTable against
61+ // unbounded mutual recursion, which would otherwise let a deeply nested
62+ // document overflow the goroutine stack (an unrecoverable fatal error).
63+ nesting int
5864}
5965
66+ // maxValueNesting is the maximum depth of nested arrays and inline tables the
67+ // parser accepts. Beyond it, parsing fails with a ParserError instead of
68+ // risking a stack overflow. Real-world TOML documents nest only a handful of
69+ // levels deep, so this bound is generous; it matches the limit used by the
70+ // standard library's encoding/json.
71+ const maxValueNesting = 10000
72+
6073// Data returns the slice provided to the last call to Reset.
6174func (p * Parser ) Data () []byte {
6275 return p .data
@@ -92,6 +105,7 @@ func (p *Parser) Reset(b []byte) {
92105 p .left = b
93106 p .nodes = p .nodes [:0 ]
94107 p .err = nil
108+ p .nesting = 0
95109}
96110
97111// Error returns any error that has occurred during parsing.
@@ -513,10 +527,24 @@ func (p *Parser) parseVal(b []byte) (int32, []byte, error) {
513527 return p .parseKeyword (b , "inf" , Float )
514528 case c == 'n' :
515529 return p .parseKeyword (b , "nan" , Float )
516- case c == '[' :
517- return p .parseValArray (b )
518- case c == '{' :
519- return p .parseInlineTable (b )
530+ case c == '[' || c == '{' :
531+ // Arrays and inline tables recurse back into parseVal for each of
532+ // their elements. Bound that recursion so a document with millions of
533+ // nested brackets or braces cannot overflow the goroutine stack.
534+ if p .nesting >= maxValueNesting {
535+ return 0 , nil , NewParserError (b [:1 ], "arrays and inline tables are nested more than the maximum of %d levels deep" , maxValueNesting )
536+ }
537+ p .nesting ++
538+ var h int32
539+ var rest []byte
540+ var err error
541+ if c == '[' {
542+ h , rest , err = p .parseValArray (b )
543+ } else {
544+ h , rest , err = p .parseInlineTable (b )
545+ }
546+ p .nesting --
547+ return h , rest , err
520548 case c == '+' || c == '-' :
521549 return p .parseIntOrFloat (b )
522550 case c >= '0' && c <= '9' :
0 commit comments