Skip to content

Commit dcbfb71

Browse files
committed
fallback: normalize buffer views before counting bytes
1 parent 874b828 commit dcbfb71

2 files changed

Lines changed: 48 additions & 4 deletions

File tree

‎msgpack/fallback.py‎

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,9 @@ def _get_data_from_buffer(obj):
7777
view = memoryview(obj)
7878
if view.itemsize != 1:
7979
raise ValueError("cannot unpack from multi-byte object")
80-
return view
80+
if not view.c_contiguous:
81+
return memoryview(view.tobytes())
82+
return view.cast("B")
8183

8284

8385
def unpackb(packed, **kwargs):
@@ -92,6 +94,7 @@ def unpackb(packed, **kwargs):
9294
9395
See :class:`Unpacker` for options.
9496
"""
97+
packed = _get_data_from_buffer(packed)
9598
unpacker = Unpacker(None, max_buffer_size=len(packed), **kwargs)
9699
unpacker.feed(packed)
97100
try:
@@ -339,7 +342,7 @@ def feed(self, next_bytes):
339342
self._buf_checkpoint = 0
340343

341344
# Use extend here: INPLACE_ADD += doesn't reliably typecast memoryview in jython
342-
self._buffer.extend(view if view.contiguous else view.tobytes())
345+
self._buffer.extend(view)
343346
view.release()
344347

345348
def _consume(self):

‎test/test_buffer.py‎

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
from pytest import raises
1+
from pytest import mark, raises
22

3-
from msgpack import Packer, packb, unpackb
3+
from msgpack import BufferFull, Packer, Unpacker, packb, unpackb
44

55

66
def test_unpack_buffer():
@@ -47,3 +47,44 @@ def test_packer_getbuffer():
4747
buffer.release()
4848
packer.pack(42)
4949
assert bytes(packer) == b"\x92*\xa5hello*"
50+
51+
52+
@mark.parametrize("shape", [(2, 3), (3, 2), (1, 6)])
53+
def test_unpack_multidimensional_buffer(shape):
54+
packed = packb(b"abcd")
55+
view = memoryview(packed).cast("B", shape)
56+
assert unpackb(view) == b"abcd"
57+
58+
unpacker = Unpacker(max_buffer_size=len(packed))
59+
unpacker.feed(view)
60+
assert unpacker.unpack() == b"abcd"
61+
62+
63+
def test_feed_multidimensional_buffer_limit():
64+
view = memoryview(packb(b"abcd")).cast("B", (2, 3))
65+
unpacker = Unpacker(max_buffer_size=5)
66+
unpacker.feed(packb(42))
67+
with raises(BufferFull):
68+
unpacker.feed(view)
69+
assert unpacker.unpack() == 42
70+
unpacker.feed(packb(43))
71+
assert unpacker.unpack() == 43
72+
73+
74+
def test_unpack_scalar_buffer():
75+
view = memoryview(packb(42)).cast("B", ())
76+
assert unpackb(view) == 42
77+
unpacker = Unpacker()
78+
unpacker.feed(view)
79+
assert unpacker.unpack() == 42
80+
81+
82+
def test_unpack_strided_multidimensional_buffer():
83+
packed = packb(b"abcd")
84+
padded = packed[:3] + b"xxx" + packed[3:] + b"xxx"
85+
view = memoryview(padded).cast("B", (4, 3))[::2]
86+
assert not view.contiguous
87+
assert unpackb(view) == b"abcd"
88+
unpacker = Unpacker(max_buffer_size=len(packed))
89+
unpacker.feed(view)
90+
assert unpacker.unpack() == b"abcd"

0 commit comments

Comments
 (0)