Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions msgpack/_unpacker.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,7 @@ cdef class Unpacker:

def __cinit__(self):
self.buf = NULL
unpack_init(&self.ctx)

Comment thread
methane marked this conversation as resolved.
Outdated
def __dealloc__(self):
unpack_clear(&self.ctx)
Expand All @@ -338,6 +339,12 @@ cdef class Unpacker:
Py_ssize_t max_ext_len=-1):
cdef const char *cerr=NULL

unpack_clear(&self.ctx)
unpack_init(&self.ctx)
if self.buf != NULL:
PyMem_Free(self.buf)
self.buf = NULL

self.object_hook = object_hook
self.object_pairs_hook = object_pairs_hook
self.list_hook = list_hook
Expand Down
36 changes: 36 additions & 0 deletions test/test_unpack.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import gc
import sys
import weakref
from io import BytesIO

from pytest import mark, raises
Expand Down Expand Up @@ -87,3 +89,37 @@ def test_unpacker_tell_read_bytes():
assert obj == unp
assert pos == unpacker.tell()
assert unpacker.read_bytes(n) == raw


@mark.skipif(
Unpacker.__module__ == "msgpack.fallback",
reason="specific to C extension reinit leak",
)
def test_unpacker_reinit_clears_partial_state():
refs = []

class Marker:
pass

def hook(code, data):
obj = Marker()
refs.append(weakref.ref(obj))
return obj

unpacker = Unpacker(ext_hook=hook, strict_map_key=False)
# Keep parser state mid-map with a live key object from ext_hook.
# Encodes: [ {ExtType(1, b"a"): <missing value>} ].
unpacker.feed(b"\x91\x81\xd4\x01a")
with raises(OutOfData):
unpacker.unpack()
assert len(refs) == 1
assert refs[0]() is not None

unpacker.__init__()
gc.collect()
assert refs[0]() is None
with raises(OutOfData):
unpacker.unpack()

unpacker.feed(packb({"a": 1}))
assert unpacker.unpack() == {"a": 1}