From 97ba6ca0d29c1e8a5b30112f13f37a4d6b3c4492 Mon Sep 17 00:00:00 2001 From: Inada Naoki Date: Wed, 3 Jun 2026 22:17:26 +0900 Subject: [PATCH 1/6] skip ci: remove unneeded CIBW_SKIP option --- .github/workflows/wheel.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/wheel.yml b/.github/workflows/wheel.yml index fb78688..56b31f0 100644 --- a/.github/workflows/wheel.yml +++ b/.github/workflows/wheel.yml @@ -48,7 +48,7 @@ jobs: env: CIBW_TEST_REQUIRES: "pytest" CIBW_TEST_COMMAND: "pytest {package}/test" - CIBW_SKIP: "pp* cp38-* cp39-* cp310-win_arm64" + CIBW_SKIP: "cp38-* cp39-* cp310-win_arm64" CIBW_ARCHS: ${{ matrix.cibw_archs || 'auto' }} - name: Build sdist From c410a388c58d55091736e510cad064977a12cb8b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 11 Jun 2026 11:54:05 +0900 Subject: [PATCH 2/6] Bump pypa/cibuildwheel from 3.4.1 to 4.0.0 (#691) --- .github/workflows/wheel.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/wheel.yml b/.github/workflows/wheel.yml index 56b31f0..a3d80b5 100644 --- a/.github/workflows/wheel.yml +++ b/.github/workflows/wheel.yml @@ -44,7 +44,7 @@ jobs: platforms: ${{ matrix.cibw_archs }} - name: Build - uses: pypa/cibuildwheel@8d2b08b68458a16aeb24b64e68a09ab1c8e82084 # v3.4.1 + uses: pypa/cibuildwheel@f03ac7617d6cff873ccf24cc0d567ef5ba5a9e6d # v4.0.0 env: CIBW_TEST_REQUIRES: "pytest" CIBW_TEST_COMMAND: "pytest {package}/test" From 11ed0a5110c1920b85b7d24d9414f480983e0f16 Mon Sep 17 00:00:00 2001 From: Inada Naoki Date: Thu, 11 Jun 2026 12:29:41 +0900 Subject: [PATCH 3/6] release v1.2.0 (#692) --- CHANGELOG.md | 2 +- msgpack/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 63cfcce..a29b4b2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # 1.2.0 -Release Date: TBD +Release Date: 2026-06-11 - Support free threaded Python. #654, #686 - Dropped support for Python 3.9. #656 diff --git a/msgpack/__init__.py b/msgpack/__init__.py index f7346d0..f053abd 100644 --- a/msgpack/__init__.py +++ b/msgpack/__init__.py @@ -5,7 +5,7 @@ from .exceptions import * # noqa: F403 from .ext import ExtType, Timestamp version = (1, 2, 0) -__version__ = "1.2.0rc1" +__version__ = "1.2.0" if os.environ.get("MSGPACK_PUREPYTHON"): From 0f4f350b6f3e80f24750422673424cce5d96e15d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 16 Jun 2026 13:22:58 +0900 Subject: [PATCH 4/6] Bump pypa/cibuildwheel from 4.0.0 to 4.1.0 in the all-dependencies group (#694) --- .github/workflows/wheel.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/wheel.yml b/.github/workflows/wheel.yml index a3d80b5..92fce01 100644 --- a/.github/workflows/wheel.yml +++ b/.github/workflows/wheel.yml @@ -44,7 +44,7 @@ jobs: platforms: ${{ matrix.cibw_archs }} - name: Build - uses: pypa/cibuildwheel@f03ac7617d6cff873ccf24cc0d567ef5ba5a9e6d # v4.0.0 + uses: pypa/cibuildwheel@294735312765b09d24a2fbec22660ce817587d55 # v4.1.0 env: CIBW_TEST_REQUIRES: "pytest" CIBW_TEST_COMMAND: "pytest {package}/test" From 2c56ddb5d0025ed481d962c0f5d62d19dec7476d Mon Sep 17 00:00:00 2001 From: Inada Naoki Date: Fri, 19 Jun 2026 00:13:13 +0900 Subject: [PATCH 5/6] Merge commit from fork * fix Unpacker crash after unpack failure. * fixup --- msgpack/_unpacker.pyx | 8 ++++++-- msgpack/unpack_template.h | 22 +++++++++++++++------- requirements.txt | 3 ++- test/test_except.py | 26 ++++++++++++++++++++++++++ 4 files changed, 49 insertions(+), 10 deletions(-) diff --git a/msgpack/_unpacker.pyx b/msgpack/_unpacker.pyx index 4bfbe06..e0cdde4 100644 --- a/msgpack/_unpacker.pyx +++ b/msgpack/_unpacker.pyx @@ -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 diff --git a/msgpack/unpack_template.h b/msgpack/unpack_template.h index 4230661..ab5887a 100644 --- a/msgpack/unpack_template.h +++ b/msgpack/unpack_template.h @@ -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 diff --git a/requirements.txt b/requirements.txt index 9e4643b..7991e3f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,4 @@ -Cython==3.2.1 +cython==3.2.5 setuptools==78.1.1 +pytest build diff --git a/test/test_except.py b/test/test_except.py index c04b110..a3bf467 100644 --- a/test/test_except.py +++ b/test/test_except.py @@ -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) From 448d43f5dcca7b3a2b0810e161af0a6431d90071 Mon Sep 17 00:00:00 2001 From: Inada Naoki Date: Fri, 19 Jun 2026 00:33:29 +0900 Subject: [PATCH 6/6] release v1.2.1 (#698) Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- CHANGELOG.md | 9 +++++++++ README.md | 6 +++++- msgpack/__init__.py | 4 ++-- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a29b4b2..b8fbd8c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 Release Date: 2026-06-11 diff --git a/README.md b/README.md index 223742d..e66d454 100644 --- a/README.md +++ b/README.md @@ -72,6 +72,10 @@ for unpacked in unpacker: 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 @@ -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 pure Python implementation (`msgpack.fallback`) is used for Python 2. - + * msgpack 1.0.6 drops official support of Python 2.7, as pip and GitHub Action "setup-python" no longer supports Python 2.7. diff --git a/msgpack/__init__.py b/msgpack/__init__.py index f053abd..eeb85af 100644 --- a/msgpack/__init__.py +++ b/msgpack/__init__.py @@ -4,8 +4,8 @@ import os from .exceptions import * # noqa: F403 from .ext import ExtType, Timestamp -version = (1, 2, 0) -__version__ = "1.2.0" +version = (1, 2, 1) +__version__ = "1.2.1" if os.environ.get("MSGPACK_PUREPYTHON"):