Skip to content

Commit 1d6e48e

Browse files
authored
Merge pull request nspcc-dev#2904 from nspcc-dev/export-deserialization-context
vm: export deserialization context
2 parents bd26b9d + 25ed5fc commit 1d6e48e

File tree

2 files changed

+43
-2
lines changed

2 files changed

+43
-2
lines changed

pkg/vm/stackitem/serialization.go

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,27 @@ func Deserialize(data []byte) (Item, error) {
232232
return item, nil
233233
}
234234

235+
// DeserializeLimited returns Item deserialized from the given byte slice. limit
236+
// restricts the maximum number of items deserialized item can contain (including
237+
// itself). The default limit of MaxDeserialized is used if non-positive limit is
238+
// specified.
239+
func DeserializeLimited(data []byte, limit int) (Item, error) {
240+
r := io.NewBinReaderFromBuf(data)
241+
dc := deserContext{
242+
BinReader: r,
243+
allowInvalid: false,
244+
limit: MaxDeserialized,
245+
}
246+
if limit > 0 {
247+
dc.limit = limit
248+
}
249+
item := dc.decodeBinary()
250+
if r.Err != nil {
251+
return nil, r.Err
252+
}
253+
return item, nil
254+
}
255+
235256
// DecodeBinary decodes the previously serialized Item from the given
236257
// reader. It's similar to the io.Serializable's DecodeBinary() but implemented
237258
// as a function because Item itself is an interface. Caveat: always check
@@ -283,7 +304,7 @@ func (r *deserContext) decodeBinary() Item {
283304
return NewBigInteger(num)
284305
case ArrayT, StructT:
285306
size := int(r.ReadVarUint())
286-
if size > MaxDeserialized {
307+
if size > r.limit {
287308
r.Err = errTooBigElements
288309
return nil
289310
}
@@ -298,7 +319,7 @@ func (r *deserContext) decodeBinary() Item {
298319
return NewStruct(arr)
299320
case MapT:
300321
size := int(r.ReadVarUint())
301-
if size > MaxDeserialized {
322+
if size > r.limit/2 {
302323
r.Err = errTooBigElements
303324
return nil
304325
}

pkg/vm/stackitem/serialization_test.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,26 @@ func TestDeserializeTooManyElements(t *testing.T) {
209209
require.True(t, errors.Is(err, ErrTooBig), err)
210210
}
211211

212+
func TestDeserializeLimited(t *testing.T) {
213+
customLimit := MaxDeserialized + 1
214+
item := Make(0)
215+
for i := 0; i < customLimit-1; i++ { // 1 for zero inner element.
216+
item = Make([]Item{item})
217+
}
218+
data, err := Serialize(item)
219+
require.NoError(t, err)
220+
actual, err := DeserializeLimited(data, customLimit)
221+
require.NoError(t, err)
222+
require.Equal(t, item, actual)
223+
224+
item = Make([]Item{item})
225+
data, err = Serialize(item)
226+
require.NoError(t, err)
227+
_, err = DeserializeLimited(data, customLimit)
228+
require.Error(t, err)
229+
require.True(t, errors.Is(err, ErrTooBig), err)
230+
}
231+
212232
func BenchmarkEncodeBinary(b *testing.B) {
213233
arr := getBigArray(15)
214234

0 commit comments

Comments
 (0)