From fecd765a405e65fbab30f8e56df9a317dcfa642a Mon Sep 17 00:00:00 2001 From: Inada Naoki Date: Fri, 30 Oct 2026 06:55:05 +0000 Subject: [PATCH] Reject non-callable ext_hook consistently in C extension --- msgpack/_unpacker.pyx | 9 ++++----- test/test_extension.py | 28 ++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 5 deletions(-) diff --git a/msgpack/_unpacker.pyx b/msgpack/_unpacker.pyx index 0801a4f9..3c81808f 100644 --- a/msgpack/_unpacker.pyx +++ b/msgpack/_unpacker.pyx @@ -71,7 +71,7 @@ cdef inline init_ctx(unpack_context *ctx, ctx.user.use_list = use_list ctx.user.raw = raw ctx.user.strict_map_key = strict_map_key - ctx.user.object_hook = ctx.user.list_hook = NULL + ctx.user.object_hook = ctx.user.list_hook = ctx.user.ext_hook = NULL ctx.user.max_str_len = max_str_len ctx.user.max_bin_len = max_bin_len ctx.user.max_array_len = max_array_len @@ -99,10 +99,9 @@ cdef inline init_ctx(unpack_context *ctx, raise TypeError("list_hook must be a callable.") ctx.user.list_hook = list_hook - if ext_hook is not None: - if not PyCallable_Check(ext_hook): - raise TypeError("ext_hook must be a callable.") - ctx.user.ext_hook = ext_hook + if not PyCallable_Check(ext_hook): + raise TypeError("ext_hook must be a callable.") + ctx.user.ext_hook = ext_hook if timestamp < 0 or 3 < timestamp: raise ValueError("timestamp must be 0..3") diff --git a/test/test_extension.py b/test/test_extension.py index 61852f15..b9d8aa68 100644 --- a/test/test_extension.py +++ b/test/test_extension.py @@ -1,9 +1,37 @@ import array +import pytest + import msgpack from msgpack import ExtType +@pytest.mark.parametrize("ext_hook", [None, 0, "hook", []]) +def test_unpackb_invalid_ext_hook(ext_hook): + with pytest.raises(TypeError, match="ext_hook.*callable"): + msgpack.unpackb(b"\xc0", ext_hook=ext_hook) + + +@pytest.mark.parametrize("ext_hook", [None, 0, "hook", []]) +def test_unpacker_invalid_ext_hook(ext_hook): + with pytest.raises(TypeError, match="ext_hook.*callable"): + msgpack.Unpacker(ext_hook=ext_hook) + + +@pytest.mark.parametrize("ext_hook", [None, 0, "hook", []]) +def test_unpacker_reinit_invalid_ext_hook(ext_hook): + unpacker = msgpack.Unpacker(ext_hook=lambda code, data: (code, data)) + unpacker.feed(b"\xd4\x42A") + assert unpacker.unpack() == (0x42, b"A") + + with pytest.raises(TypeError, match="ext_hook.*callable"): + unpacker.__init__(ext_hook=ext_hook) + + unpacker.__init__() + unpacker.feed(b"\xd4\x42A") + assert unpacker.unpack() == ExtType(0x42, b"A") + + def test_pack_ext_type(): def p(s): packer = msgpack.Packer(autoreset=False)