mirror of
https://github.com/msgpack/msgpack-python.git
synced 2026-06-19 06:02:09 +00:00
Compare commits
3 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
448d43f5dc | ||
|
|
2c56ddb5d0 | ||
|
|
0f4f350b6f |
8 changed files with 66 additions and 14 deletions
2
.github/workflows/wheel.yml
vendored
2
.github/workflows/wheel.yml
vendored
|
|
@ -44,7 +44,7 @@ jobs:
|
||||||
platforms: ${{ matrix.cibw_archs }}
|
platforms: ${{ matrix.cibw_archs }}
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
uses: pypa/cibuildwheel@f03ac7617d6cff873ccf24cc0d567ef5ba5a9e6d # v4.0.0
|
uses: pypa/cibuildwheel@294735312765b09d24a2fbec22660ce817587d55 # v4.1.0
|
||||||
env:
|
env:
|
||||||
CIBW_TEST_REQUIRES: "pytest"
|
CIBW_TEST_REQUIRES: "pytest"
|
||||||
CIBW_TEST_COMMAND: "pytest {package}/test"
|
CIBW_TEST_COMMAND: "pytest {package}/test"
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,12 @@
|
||||||
|
# 1.2.1
|
||||||
|
|
||||||
|
Release Date: 2026-06-19
|
||||||
|
|
||||||
|
Fix a segfault when calling `Unpacker.unpack()` or `Unpacker.skip()` after an unpacking failure.
|
||||||
|
But note that reusing the same `Unpacker` instance after an unpacking failure is not supported.
|
||||||
|
Please create a new `Unpacker` instance instead. GHSA-6v7p-g79w-8964
|
||||||
|
|
||||||
|
|
||||||
# 1.2.0
|
# 1.2.0
|
||||||
|
|
||||||
Release Date: 2026-06-11
|
Release Date: 2026-06-11
|
||||||
|
|
|
||||||
|
|
@ -72,6 +72,10 @@ for unpacked in unpacker:
|
||||||
print(unpacked)
|
print(unpacked)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
> [!IMPORTANT]
|
||||||
|
> If `Unpacker.unpack()` stops with an exception other than `OutOfData`, that `Unpacker` cannot be reused.
|
||||||
|
> Create a new `Unpacker` when reading another stream.
|
||||||
|
|
||||||
|
|
||||||
### Packing/unpacking of custom data types
|
### Packing/unpacking of custom data types
|
||||||
|
|
||||||
|
|
@ -220,7 +224,7 @@ When upgrading from msgpack-0.4 or earlier, do `pip uninstall msgpack-python` be
|
||||||
|
|
||||||
* The extension module no longer supports Python 2.
|
* The extension module no longer supports Python 2.
|
||||||
The pure Python implementation (`msgpack.fallback`) is used for Python 2.
|
The pure Python implementation (`msgpack.fallback`) is used for Python 2.
|
||||||
|
|
||||||
* msgpack 1.0.6 drops official support of Python 2.7, as pip and
|
* msgpack 1.0.6 drops official support of Python 2.7, as pip and
|
||||||
GitHub Action "setup-python" no longer supports Python 2.7.
|
GitHub Action "setup-python" no longer supports Python 2.7.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,8 @@ import os
|
||||||
from .exceptions import * # noqa: F403
|
from .exceptions import * # noqa: F403
|
||||||
from .ext import ExtType, Timestamp
|
from .ext import ExtType, Timestamp
|
||||||
|
|
||||||
version = (1, 2, 0)
|
version = (1, 2, 1)
|
||||||
__version__ = "1.2.0"
|
__version__ = "1.2.1"
|
||||||
|
|
||||||
|
|
||||||
if os.environ.get("MSGPACK_PUREPYTHON"):
|
if os.environ.get("MSGPACK_PUREPYTHON"):
|
||||||
|
|
|
||||||
|
|
@ -51,6 +51,7 @@ cdef extern from "unpack.h":
|
||||||
execute_fn unpack_skip
|
execute_fn unpack_skip
|
||||||
execute_fn read_array_header
|
execute_fn read_array_header
|
||||||
execute_fn read_map_header
|
execute_fn read_map_header
|
||||||
|
|
||||||
void unpack_init(unpack_context* ctx)
|
void unpack_init(unpack_context* ctx)
|
||||||
object unpack_data(unpack_context* ctx)
|
object unpack_data(unpack_context* ctx)
|
||||||
void unpack_clear(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:
|
if off < buf_len:
|
||||||
raise ExtraData(obj, PyBytes_FromStringAndSize(buf+off, buf_len-off))
|
raise ExtraData(obj, PyBytes_FromStringAndSize(buf+off, buf_len-off))
|
||||||
return obj
|
return obj
|
||||||
|
|
||||||
unpack_clear(&ctx)
|
unpack_clear(&ctx)
|
||||||
if ret == 0:
|
if ret == 0:
|
||||||
raise ValueError("Unpack failed: incomplete input")
|
raise ValueError("Unpack failed: incomplete input")
|
||||||
|
|
@ -475,7 +477,7 @@ cdef class Unpacker:
|
||||||
obj = unpack_data(&self.ctx)
|
obj = unpack_data(&self.ctx)
|
||||||
unpack_init(&self.ctx)
|
unpack_init(&self.ctx)
|
||||||
return obj
|
return obj
|
||||||
elif ret == 0:
|
if ret == 0:
|
||||||
if self.file_like is not None:
|
if self.file_like is not None:
|
||||||
self.read_from_file()
|
self.read_from_file()
|
||||||
continue
|
continue
|
||||||
|
|
@ -483,7 +485,9 @@ cdef class Unpacker:
|
||||||
raise StopIteration("No more data to unpack.")
|
raise StopIteration("No more data to unpack.")
|
||||||
else:
|
else:
|
||||||
raise OutOfData("No more data to unpack.")
|
raise OutOfData("No more data to unpack.")
|
||||||
elif ret == -2:
|
|
||||||
|
unpack_clear(&self.ctx)
|
||||||
|
if ret == -2:
|
||||||
raise FormatError
|
raise FormatError
|
||||||
elif ret == -3:
|
elif ret == -3:
|
||||||
raise StackError
|
raise StackError
|
||||||
|
|
|
||||||
|
|
@ -72,15 +72,14 @@ static inline PyObject* unpack_data(unpack_context* ctx)
|
||||||
|
|
||||||
static inline void unpack_clear(unpack_context *ctx)
|
static inline void unpack_clear(unpack_context *ctx)
|
||||||
{
|
{
|
||||||
unsigned int i;
|
for (unsigned int i = 0; i < ctx->top; i++) {
|
||||||
for (i = 1; i < ctx->top; i++) {
|
|
||||||
Py_CLEAR(ctx->stack[i].obj);
|
|
||||||
/* map_key holds a live reference only while waiting for the value */
|
/* map_key holds a live reference only while waiting for the value */
|
||||||
if (ctx->stack[i].ct == CT_MAP_VALUE) {
|
if (ctx->stack[i].ct == CT_MAP_VALUE) {
|
||||||
Py_CLEAR(ctx->stack[i].map_key);
|
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)
|
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 0xd5: // fixext 2
|
||||||
case 0xd6: // fixext 4
|
case 0xd6: // fixext 4
|
||||||
case 0xd7: // fixext 8
|
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,
|
(1 << (((unsigned int)*p) & 0x03))+1,
|
||||||
_ext_zero);
|
_ext_zero);
|
||||||
case 0xd8: // fixext 16
|
case 0xd8: // fixext 16
|
||||||
|
|
@ -344,6 +343,7 @@ _push:
|
||||||
goto _header_again;
|
goto _header_again;
|
||||||
case CT_MAP_VALUE:
|
case CT_MAP_VALUE:
|
||||||
if(construct_cb(_map_item)(user, c->count, &c->obj, c->map_key, obj) < 0) { goto _failed; }
|
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) {
|
if(++c->count == c->size) {
|
||||||
obj = c->obj;
|
obj = c->obj;
|
||||||
if (construct_cb(_map_end)(user, &obj) < 0) { goto _failed; }
|
if (construct_cb(_map_end)(user, &obj) < 0) { goto _failed; }
|
||||||
|
|
@ -406,10 +406,18 @@ _end:
|
||||||
#undef start_container
|
#undef start_container
|
||||||
|
|
||||||
static int unpack_construct(unpack_context *ctx, const char *data, Py_ssize_t len, Py_ssize_t *off) {
|
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) {
|
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
|
#define unpack_container_header read_array_header
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
Cython==3.2.1
|
cython==3.2.5
|
||||||
setuptools==78.1.1
|
setuptools==78.1.1
|
||||||
|
pytest
|
||||||
build
|
build
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,22 @@ def test_raise_from_object_hook():
|
||||||
object_pairs_hook=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 test_raise_from_list_hook():
|
||||||
def hook(lst: list) -> list:
|
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)
|
packed = packb(valid, use_bin_type=True)
|
||||||
result = unpackb(packed, raw=False, strict_map_key=True, object_pairs_hook=list)
|
result = unpackb(packed, raw=False, strict_map_key=True, object_pairs_hook=list)
|
||||||
assert result == [("key", "value")]
|
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