From 6476b9ae7019bedd9324786ff47bc25693e01b60 Mon Sep 17 00:00:00 2001 From: Luke Shumaker Date: Mon, 15 Aug 2022 19:49:46 -0600 Subject: Push nesting-depth checks down in to the parser [ci-skip] --- decode.go | 15 +++++---------- errors.go | 15 ++++++++++++--- parse.go | 15 ++++++++++++++- 3 files changed, 31 insertions(+), 14 deletions(-) diff --git a/decode.go b/decode.go index e4fdd77..b1cc90f 100644 --- a/decode.go +++ b/decode.go @@ -45,6 +45,8 @@ type Decoder struct { stack []decodeStackItem } +const maxNestingDepth = 10000 + func NewDecoder(r io.Reader) *Decoder { rr, ok := r.(io.RuneReader) if !ok { @@ -54,6 +56,9 @@ func NewDecoder(r io.Reader) *Decoder { io: &noWSRuneTypeScanner{ inner: &runeTypeScannerImpl{ inner: rr, + parser: Parser{ + MaxDepth: maxNestingDepth, + }, }, }, } @@ -70,18 +75,8 @@ func (dec *Decoder) More() bool { return e == nil && t != RuneTypeEOF } -const maxNestingDepth = 10000 - func (dec *Decoder) stackPush(par reflect.Type, idx any) { dec.stack = append(dec.stack, decodeStackItem{par, idx}) - if len(dec.stack) > maxNestingDepth { - panic(decodeError{ - Field: dec.stackStr(), - FieldParent: dec.stackParent(), - FieldName: dec.stackName(), - Err: ErrDecodeExceededMaxDepth, - }) - } } func (dec *Decoder) stackPop() { dec.stack = dec.stack[:len(dec.stack)-1] diff --git a/errors.go b/errors.go index a5a4080..cee82f7 100644 --- a/errors.go +++ b/errors.go @@ -6,10 +6,21 @@ package lowmemjson import ( "encoding/json" + "errors" "fmt" "reflect" "strings" - "errors" +) + +// parser errors /////////////////////////////////////////////////////////////////////////////////// + +type ParseError struct { + Err error + Offset int64 +} + +var ( + ErrParserExceededMaxDepth = errors.New("exceeded max depth") ) // low-level decode errors ///////////////////////////////////////////////////////////////////////// @@ -65,8 +76,6 @@ func (e *DecodeTypeError) Error() string { func (e *DecodeTypeError) Unwrap() error { return e.Err } -var ErrDecodeExceededMaxDepth = errors.New("exceeded max depth") - // high-level decode errors //////////////////////////////////////////////////////////////////////// // A *DecodeArgumentError is returned from Decode if the argument is diff --git a/parse.go b/parse.go index 23df5bc..fb72280 100644 --- a/parse.go +++ b/parse.go @@ -204,6 +204,11 @@ func (t RuneType) IsNumber() bool { } type Parser struct { + // Setting MaxError to a value greater than 0 causes + // HandleRune to return ErrParserExceededMaxDepth if + // objects/arrays become nested more deeply than this. + MaxDepth int + initialized bool err error @@ -286,7 +291,9 @@ func (par *Parser) stackString() string { // Reset all Parser state. func (par *Parser) Reset() { - *par = Parser{} + *par = Parser{ + MaxDepth: par.MaxDepth, + } } // HandleEOF feeds EOF to the Parser. The returned RuneType is either @@ -370,8 +377,14 @@ func (par *Parser) HandleRune(c rune) (RuneType, error) { case 0x0020, 0x000A, 0x000D, 0x0009: return RuneTypeSpace, nil case '{': + if par.MaxDepth > 0 && len(par.stack) > par.MaxDepth { + return RuneTypeError, ErrParserExceededMaxDepth + } return par.replaceState(RuneTypeObjectBeg), nil case '[': + if par.MaxDepth > 0 && len(par.stack) > par.MaxDepth { + return RuneTypeError, ErrParserExceededMaxDepth + } return par.replaceState(RuneTypeArrayBeg), nil case '"': return par.replaceState(RuneTypeStringBeg), nil -- cgit v1.2.3-2-g168b