diff --git a/decode_map.go b/decode_map.go index 7ba8e10..fc3c3e7 100644 --- a/decode_map.go +++ b/decode_map.go @@ -221,7 +221,12 @@ func (d *Decoder) DecodeUntypedMap() (map[interface{}]interface{}, error) { return nil, nil } - m := make(map[interface{}]interface{}, n) + ln := n + if d.flags&disableAllocLimitFlag == 0 { + ln = min(ln, maxMapSize) + } + + m := make(map[interface{}]interface{}, ln) for i := 0; i < n; i++ { mk, err := d.decodeInterfaceCond() diff --git a/msgpack_test.go b/msgpack_test.go index 6de7319..d18a207 100644 --- a/msgpack_test.go +++ b/msgpack_test.go @@ -75,6 +75,26 @@ func (t *MsgpackTest) TestLargeString() { t.Equal(dst, src) } +func (t *MsgpackTest) TestDecodeUntypedMapHugeDeclaredLen() { + // A map32 header declaring ~4G entries with no payload: the map size + // hint must be clamped at maxMapSize before allocation (with the old + // code this allocated a multi-GB map upfront), then fail decoding the + // first key. + data := []byte{0xdf, 0xff, 0xff, 0xff, 0xff} + dec := msgpack.NewDecoder(bytes.NewReader(data)) + _, err := dec.DecodeUntypedMap() + t.NotNil(err) +} + +func (t *MsgpackTest) TestDecodeUntypedMap() { + in := map[interface{}]interface{}{int8(1): "one", "two": int8(2)} + t.Nil(t.enc.Encode(in)) + + out, err := t.dec.DecodeUntypedMap() + t.Nil(err) + t.Equal(in, out) +} + func (t *MsgpackTest) TestSliceOfStructs() { in := []*nameStruct{{"hello"}} var out []*nameStruct