diff options
-rw-r--r-- | decode.go | 15 | ||||
-rw-r--r-- | errors.go | 15 | ||||
-rw-r--r-- | parse.go | 15 |
3 files changed, 31 insertions, 14 deletions
@@ -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] @@ -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 @@ -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 |