diff --git a/README.md b/README.md index 9a11219e..8b4b2c7e 100644 --- a/README.md +++ b/README.md @@ -362,7 +362,7 @@ See [Options](#options) section for details about each setting. | IndefLength | **IndefLengthAllowed**, IndefLengthForbidden | | TagsMd | **TagsAllowed**, TagsForbidden | | ExtraReturnErrors | **ExtraDecErrorNone**, ExtraDecErrorUnknownField | -| MaxNestedLevels | **32**, can be set to [4, 256] | +| MaxNestedLevels | **32**, can be set to [4, 65535] | | MaxArrayElements | **131072**, can be set to [16, 2147483647] | | MaxMapPairs | **131072**, can be set to [16, 2147483647] | @@ -697,7 +697,7 @@ If `IntDecConvertedSigned` is used and value overflows int64, UnmarshalTypeError | DecOptions.MaxNestedLevels | Description | | -------------------------- | ----------- | -| 32 (default) | allowed setting is [4, 256] | +| 32 (default) | allowed setting is [4, 65535] |
diff --git a/decode.go b/decode.go index 79ccaf80..f7ec8822 100644 --- a/decode.go +++ b/decode.go @@ -287,7 +287,8 @@ type DecOptions struct { TimeTag DecTagMode // MaxNestedLevels specifies the max nested levels allowed for any combination of CBOR array, maps, and tags. - // Default is 32 levels and it can be set to [4, 256]. + // Default is 32 levels and it can be set to [4, 65535]. Note that higher maximum levels of nesting can + // require larger amounts of stack to deserialize. Don't increase this higher than you require. MaxNestedLevels int // MaxArrayElements specifies the max number of elements for CBOR arrays. @@ -402,8 +403,8 @@ func (opts DecOptions) decMode() (*decMode, error) { } if opts.MaxNestedLevels == 0 { opts.MaxNestedLevels = 32 - } else if opts.MaxNestedLevels < 4 || opts.MaxNestedLevels > 256 { - return nil, errors.New("cbor: invalid MaxNestedLevels " + strconv.Itoa(opts.MaxNestedLevels) + " (range is [4, 256])") + } else if opts.MaxNestedLevels < 4 || opts.MaxNestedLevels > 65535 { + return nil, errors.New("cbor: invalid MaxNestedLevels " + strconv.Itoa(opts.MaxNestedLevels) + " (range is [4, 65535])") } if opts.MaxArrayElements == 0 { opts.MaxArrayElements = defaultMaxArrayElements diff --git a/decode_test.go b/decode_test.go index dc7ee132..3c1725e9 100644 --- a/decode_test.go +++ b/decode_test.go @@ -3131,6 +3131,44 @@ func TestUnmarshalIntoMapError(t *testing.T) { } } +func TestUnmarshalDeepNesting(t *testing.T) { + // Construct this object rather than embed such a large constant in the code + type TestNode struct { + Value int + Child *TestNode + } + n := &TestNode{Value: 0} + root := n + for i := 0; i < 65534; i++ { + child := &TestNode{Value: i} + n.Child = child + n = child + } + em, err := EncOptions{}.EncMode() + if err != nil { + t.Errorf("EncMode() returned error %v", err) + } + cborData, err := em.Marshal(root) + if err != nil { + t.Errorf("Marshal() deeply nested object returned error %v", err) + } + + // Try unmarshal it + dm, err := DecOptions{MaxNestedLevels: 65535}.DecMode() + if err != nil { + t.Errorf("DecMode() returned error %v", err) + } + var readback TestNode + err = dm.Unmarshal(cborData, &readback) + if err != nil { + t.Errorf("Unmarshal() of deeply nested object returned error: %v", err) + } + if !reflect.DeepEqual(root, &readback) { + t.Errorf("Unmarshal() of deeply nested object did not match\nGot: %#v\n Want: %#v\n", + &readback, root) + } +} + func TestStructToArrayError(t *testing.T) { type coseHeader struct { Alg int `cbor:"1,keyasint,omitempty"` @@ -3291,12 +3329,12 @@ func TestDecModeInvalidMaxNestedLevel(t *testing.T) { { name: "MaxNestedLevels < 4", opts: DecOptions{MaxNestedLevels: 1}, - wantErrorMsg: "cbor: invalid MaxNestedLevels 1 (range is [4, 256])", + wantErrorMsg: "cbor: invalid MaxNestedLevels 1 (range is [4, 65535])", }, { - name: "MaxNestedLevels > 256", - opts: DecOptions{MaxNestedLevels: 257}, - wantErrorMsg: "cbor: invalid MaxNestedLevels 257 (range is [4, 256])", + name: "MaxNestedLevels > 65535", + opts: DecOptions{MaxNestedLevels: 65536}, + wantErrorMsg: "cbor: invalid MaxNestedLevels 65536 (range is [4, 65535])", }, } for _, tc := range testCases {