mirror of
https://github.com/msgpack/msgpack-python.git
synced 2026-06-26 10:40:30 +00:00
parent
7082130739
commit
cf3fd2b061
2 changed files with 60 additions and 28 deletions
|
|
@ -305,6 +305,8 @@ cdef class Unpacker:
|
|||
Raises ``OutOfData`` when *packed* is incomplete.
|
||||
Raises ``FormatError`` when *packed* is not valid msgpack.
|
||||
Raises ``StackError`` when *packed* contains too nested.
|
||||
Raises ``RuntimeError`` when ``feed()`` is called while unpacking
|
||||
is in progress (e.g. from a hook).
|
||||
Other exceptions can be raised during unpacking.
|
||||
"""
|
||||
cdef unpack_context ctx
|
||||
|
|
@ -318,6 +320,7 @@ cdef class Unpacker:
|
|||
cdef object unicode_errors
|
||||
cdef Py_ssize_t max_buffer_size
|
||||
cdef uint64_t stream_offset
|
||||
cdef bint _unpacking
|
||||
|
||||
def __dealloc__(self):
|
||||
unpack_clear(&self.ctx)
|
||||
|
|
@ -381,6 +384,7 @@ cdef class Unpacker:
|
|||
self.buf_head = 0
|
||||
self.buf_tail = 0
|
||||
self.stream_offset = 0
|
||||
self._unpacking = False
|
||||
|
||||
if unicode_errors is not None:
|
||||
self.unicode_errors = unicode_errors
|
||||
|
|
@ -398,6 +402,11 @@ cdef class Unpacker:
|
|||
cdef char* buf
|
||||
cdef Py_ssize_t buf_len
|
||||
|
||||
if self._unpacking:
|
||||
raise RuntimeError(
|
||||
"Unpacker.feed() cannot be called while unpacking is in progress"
|
||||
)
|
||||
|
||||
if self.file_like is not None:
|
||||
raise AssertionError(
|
||||
"unpacker.feed() is not be able to use with `file_like`.")
|
||||
|
|
@ -465,36 +474,40 @@ cdef class Unpacker:
|
|||
cdef object obj
|
||||
cdef Py_ssize_t prev_head
|
||||
|
||||
while 1:
|
||||
prev_head = self.buf_head
|
||||
if prev_head < self.buf_tail:
|
||||
ret = execute(&self.ctx, self.buf, self.buf_tail, &self.buf_head)
|
||||
self.stream_offset += self.buf_head - prev_head
|
||||
else:
|
||||
ret = 0
|
||||
|
||||
if ret == 1:
|
||||
obj = unpack_data(&self.ctx)
|
||||
unpack_init(&self.ctx)
|
||||
return obj
|
||||
if ret == 0:
|
||||
if self.file_like is not None:
|
||||
self.read_from_file()
|
||||
continue
|
||||
if iter:
|
||||
raise StopIteration("No more data to unpack.")
|
||||
self._unpacking = True
|
||||
try:
|
||||
while 1:
|
||||
prev_head = self.buf_head
|
||||
if prev_head < self.buf_tail:
|
||||
ret = execute(&self.ctx, self.buf, self.buf_tail, &self.buf_head)
|
||||
self.stream_offset += self.buf_head - prev_head
|
||||
else:
|
||||
raise OutOfData("No more data to unpack.")
|
||||
ret = 0
|
||||
|
||||
unpack_clear(&self.ctx)
|
||||
if ret == -2:
|
||||
raise FormatError
|
||||
elif ret == -3:
|
||||
raise StackError
|
||||
elif PyErr_Occurred():
|
||||
raise
|
||||
else:
|
||||
raise ValueError("Unpack failed: error = %d" % (ret,))
|
||||
if ret == 1:
|
||||
obj = unpack_data(&self.ctx)
|
||||
unpack_init(&self.ctx)
|
||||
return obj
|
||||
if ret == 0:
|
||||
if self.file_like is not None:
|
||||
self.read_from_file()
|
||||
continue
|
||||
if iter:
|
||||
raise StopIteration("No more data to unpack.")
|
||||
else:
|
||||
raise OutOfData("No more data to unpack.")
|
||||
|
||||
unpack_clear(&self.ctx)
|
||||
if ret == -2:
|
||||
raise FormatError
|
||||
elif ret == -3:
|
||||
raise StackError
|
||||
elif PyErr_Occurred():
|
||||
raise
|
||||
else:
|
||||
raise ValueError("Unpack failed: error = %d" % (ret,))
|
||||
finally:
|
||||
self._unpacking = False
|
||||
|
||||
@cython.critical_section
|
||||
def read_bytes(self, Py_ssize_t nbytes):
|
||||
|
|
|
|||
|
|
@ -123,3 +123,22 @@ def test_unpacker_reinit_clears_partial_state():
|
|||
|
||||
unpacker.feed(packb({"a": 1}))
|
||||
assert unpacker.unpack() == {"a": 1}
|
||||
|
||||
|
||||
@mark.skipif(
|
||||
Unpacker.__module__ == "msgpack.fallback",
|
||||
reason="reentrant guard is implemented in C extension only",
|
||||
)
|
||||
def test_unpacker_reentrant_feed():
|
||||
import struct
|
||||
|
||||
def ext_hook(code, data):
|
||||
# re-entrant feed on the SAME unpacker, large enough to force a buffer realloc
|
||||
up.feed(b"\xc0" * 100)
|
||||
return 0
|
||||
|
||||
up = Unpacker(ext_hook=ext_hook, max_buffer_size=64 * 1024 * 1024)
|
||||
# array(11): [ ExtType(code=5, data=b'A') (fires the re-entrant hook), then 10 more elements ]
|
||||
up.feed(b"\xdc" + struct.pack(">H", 11) + b"\xd4\x05A" + b"\x2a" * 10)
|
||||
with raises(RuntimeError):
|
||||
up.unpack()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue