From c701ef8b812284ff049a8f4f29e8f5f30c3bfd01 Mon Sep 17 00:00:00 2001 From: Haim Dimer Date: Wed, 12 Aug 2026 11:33:39 -0700 Subject: [PATCH] Convert Packer's buf_size once buf_size was untyped, so Cython converted it to size_t separately for the PyMem_Malloc call and for pk.buf_size. An object whose __int__ answers differently each call made the packer allocate one size and record another, and pack.h then grew the buffer against the recorded capacity, so a large enough payload was memcpy'd past the allocation. Typing the parameter converts it once during argument unpacking, the same way Unpacker takes read_size and max_buffer_size. Fixes #723 --- msgpack/_packer.pyx | 2 +- test/test_pack.py | 21 +++++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/msgpack/_packer.pyx b/msgpack/_packer.pyx index 277239d8..e816c814 100644 --- a/msgpack/_packer.pyx +++ b/msgpack/_packer.pyx @@ -110,7 +110,7 @@ cdef class Packer: cdef bint autoreset cdef bint datetime - def __cinit__(self, buf_size=256*1024, **_kwargs): + def __cinit__(self, size_t buf_size=256*1024, **_kwargs): self.pk.buf = PyMem_Malloc(buf_size) if self.pk.buf == NULL: raise MemoryError("Unable to allocate internal buffer.") diff --git a/test/test_pack.py b/test/test_pack.py index 374d1549..f44bd557 100644 --- a/test/test_pack.py +++ b/test/test_pack.py @@ -179,3 +179,24 @@ def test_get_buffer(): expected = packb([1, 2], use_bin_type=True) assert written == expected + + +@pytest.mark.skipif( + Packer.__module__ == "msgpack.fallback", + reason="buf_size only allocates in the C extension", +) +def test_buf_size_is_converted_once(): + # Asking twice let the allocation and the recorded capacity disagree, + # so the packer overflowed a buffer smaller than the size it recorded. + class Counting: + count = 0 + + def __int__(self): + self.count += 1 + return 600 + + __index__ = __int__ + + buf_size = Counting() + Packer(buf_size=buf_size) + assert buf_size.count == 1