mirror of
https://github.com/msgpack/msgpack-python.git
synced 2026-06-18 21:52:06 +00:00
Merge commit from fork
* fix Unpacker crash after unpack failure. * fixup
This commit is contained in:
parent
0f4f350b6f
commit
2c56ddb5d0
4 changed files with 49 additions and 10 deletions
|
|
@ -51,6 +51,7 @@ cdef extern from "unpack.h":
|
|||
execute_fn unpack_skip
|
||||
execute_fn read_array_header
|
||||
execute_fn read_map_header
|
||||
|
||||
void unpack_init(unpack_context* ctx)
|
||||
object unpack_data(unpack_context* ctx)
|
||||
void unpack_clear(unpack_context* ctx)
|
||||
|
|
@ -197,6 +198,7 @@ def unpackb(object packed, *, object object_hook=None, object list_hook=None,
|
|||
if off < buf_len:
|
||||
raise ExtraData(obj, PyBytes_FromStringAndSize(buf+off, buf_len-off))
|
||||
return obj
|
||||
|
||||
unpack_clear(&ctx)
|
||||
if ret == 0:
|
||||
raise ValueError("Unpack failed: incomplete input")
|
||||
|
|
@ -475,7 +477,7 @@ cdef class Unpacker:
|
|||
obj = unpack_data(&self.ctx)
|
||||
unpack_init(&self.ctx)
|
||||
return obj
|
||||
elif ret == 0:
|
||||
if ret == 0:
|
||||
if self.file_like is not None:
|
||||
self.read_from_file()
|
||||
continue
|
||||
|
|
@ -483,7 +485,9 @@ cdef class Unpacker:
|
|||
raise StopIteration("No more data to unpack.")
|
||||
else:
|
||||
raise OutOfData("No more data to unpack.")
|
||||
elif ret == -2:
|
||||
|
||||
unpack_clear(&self.ctx)
|
||||
if ret == -2:
|
||||
raise FormatError
|
||||
elif ret == -3:
|
||||
raise StackError
|
||||
|
|
|
|||
|
|
@ -72,15 +72,14 @@ static inline PyObject* unpack_data(unpack_context* ctx)
|
|||
|
||||
static inline void unpack_clear(unpack_context *ctx)
|
||||
{
|
||||
unsigned int i;
|
||||
for (i = 1; i < ctx->top; i++) {
|
||||
Py_CLEAR(ctx->stack[i].obj);
|
||||
for (unsigned int i = 0; i < ctx->top; i++) {
|
||||
/* map_key holds a live reference only while waiting for the value */
|
||||
if (ctx->stack[i].ct == CT_MAP_VALUE) {
|
||||
Py_CLEAR(ctx->stack[i].map_key);
|
||||
}
|
||||
Py_CLEAR(ctx->stack[i].obj);
|
||||
}
|
||||
Py_CLEAR(ctx->stack[0].obj);
|
||||
unpack_init(ctx);
|
||||
}
|
||||
|
||||
static inline int unpack_execute(bool construct, unpack_context* ctx, const char* data, Py_ssize_t len, Py_ssize_t* off)
|
||||
|
|
@ -200,7 +199,7 @@ static inline int unpack_execute(bool construct, unpack_context* ctx, const char
|
|||
case 0xd5: // fixext 2
|
||||
case 0xd6: // fixext 4
|
||||
case 0xd7: // fixext 8
|
||||
again_fixed_trail_if_zero(ACS_EXT_VALUE,
|
||||
again_fixed_trail_if_zero(ACS_EXT_VALUE,
|
||||
(1 << (((unsigned int)*p) & 0x03))+1,
|
||||
_ext_zero);
|
||||
case 0xd8: // fixext 16
|
||||
|
|
@ -344,6 +343,7 @@ _push:
|
|||
goto _header_again;
|
||||
case CT_MAP_VALUE:
|
||||
if(construct_cb(_map_item)(user, c->count, &c->obj, c->map_key, obj) < 0) { goto _failed; }
|
||||
c->map_key = NULL;
|
||||
if(++c->count == c->size) {
|
||||
obj = c->obj;
|
||||
if (construct_cb(_map_end)(user, &obj) < 0) { goto _failed; }
|
||||
|
|
@ -406,10 +406,18 @@ _end:
|
|||
#undef start_container
|
||||
|
||||
static int unpack_construct(unpack_context *ctx, const char *data, Py_ssize_t len, Py_ssize_t *off) {
|
||||
return unpack_execute(1, ctx, data, len, off);
|
||||
int ret = unpack_execute(1, ctx, data, len, off);
|
||||
if (ret == -1) {
|
||||
unpack_clear(ctx);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
static int unpack_skip(unpack_context *ctx, const char *data, Py_ssize_t len, Py_ssize_t *off) {
|
||||
return unpack_execute(0, ctx, data, len, off);
|
||||
int ret = unpack_execute(0, ctx, data, len, off);
|
||||
if (ret == -1) {
|
||||
unpack_clear(ctx);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define unpack_container_header read_array_header
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
Cython==3.2.1
|
||||
cython==3.2.5
|
||||
setuptools==78.1.1
|
||||
pytest
|
||||
build
|
||||
|
|
|
|||
|
|
@ -33,6 +33,22 @@ def test_raise_from_object_hook():
|
|||
object_pairs_hook=hook,
|
||||
)
|
||||
|
||||
up = Unpacker(object_hook=hook)
|
||||
|
||||
def up_unpack(x):
|
||||
up.feed(x)
|
||||
return up.unpack()
|
||||
|
||||
raises(DummyException, up_unpack, packb({}))
|
||||
raises(DummyException, up_unpack, packb({"fizz": "buzz"}))
|
||||
raises(DummyException, up_unpack, packb({"fizz": "buzz"}))
|
||||
raises(DummyException, up_unpack, packb({"fizz": {"buzz": "spam"}}))
|
||||
raises(
|
||||
DummyException,
|
||||
up_unpack,
|
||||
packb({"fizz": {"buzz": "spam"}}),
|
||||
)
|
||||
|
||||
|
||||
def test_raise_from_list_hook():
|
||||
def hook(lst: list) -> list:
|
||||
|
|
@ -138,3 +154,13 @@ def test_strict_map_key_with_object_pairs_hook():
|
|||
packed = packb(valid, use_bin_type=True)
|
||||
result = unpackb(packed, raw=False, strict_map_key=True, object_pairs_hook=list)
|
||||
assert result == [("key", "value")]
|
||||
|
||||
|
||||
def test_unpacker_should_not_crash_after_exception():
|
||||
up = Unpacker() # default: strict_map_key=True
|
||||
up.feed(b"\x83\x73\xc4\x00") # fixmap(3): int key (rejected) + empty bin8
|
||||
try:
|
||||
up.unpack() # ValueError: int is not allowed for map key ...
|
||||
except Exception:
|
||||
pass
|
||||
up.skip() # SIGSEGV (resumes from a corrupt parser context)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue