You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
unpackb() may return corrupted ExtraData.extra for non-contiguous input #720
I found an issue in unpackb() while fuzzing Python C extension modules with Atheris and ASan/UBSan enabled.
The sanitizer initially reported memcpy-param-overlap, but the problem is not limited to sanitizer builds. The same input also produces incorrect output with the PyPI wheel, without crashing or emitting a warning.
Environment
msgpack 1.2.1
CPython 3.12
Linux x86_64
Reproducer
importmsgpack# A strided (non-contiguous) view whose logical content is b"\x00abc":# \x00 -> the integer 0# abc -> trailing bytes, so unpackb raises ExtraDatabuf=bytearray(b"\x00\xffa\xffb\xffc\xff")
view=memoryview(buf)[::2]
assertbytes(view) ==b"\x00abc"try:
msgpack.unpackb(view)
exceptmsgpack.ExtraDataase:
print(e.unpacked) # 0 -- correctprint(e.extra) # b'ab\x00' -- expected b'abc'
Reproduced on macOS 15 / arm64, CPython 3.14.6, msgpack 1.2.1 (PyPI wheel) — same output as reported, and also on current main. The pure-Python fallback (MSGPACK_PUREPYTHON=1) is correct; only _cmsgpack is affected. Any non-contiguous view triggers it — [::2] and [::-1] alike.
The underlying problem is a use-after-free. For non-contiguous input, get_data_from_buffer() releases the original view and makes a temporary contiguous copy, so buf points into memory owned by view. unpackb() then releases view in its finally block — freeing that copy — and only afterwards reads buf+off to build the ExtraData payload.
That it is really freed memory, and not just an off-by-one, is easy to show with the macOS allocator's free-poisoning:
So arbitrary heap contents can end up in ExtraData.extra. The memcpy-param-overlap ASan reports is the same event seen from the other side: PyBytes_FromStringAndSize re-allocates the just-freed block and copies it onto itself.
Unpacker.feed() uses the same helper but copies via append_buffer() before releasing, so it is unaffected.
One more data point: msgpack 1.1.1 does not silently corrupt on this input — it raises SystemError: <class 'msgpack.exceptions.ExtraData'> returned a result with an exception set (from a BufferError), presumably a different symptom of the pre-#677 buffer handling. So the silent corruption looks specific to 1.2.x; the #677 fix did not cover this path.
Activity
ThomasWaldmann commentedon Aug 3, 2026
Reproduced on macOS 15 / arm64, CPython 3.14.6, msgpack 1.2.1 (PyPI wheel) — same output as reported, and also on current
main. The pure-Python fallback (MSGPACK_PUREPYTHON=1) is correct; only_cmsgpackis affected. Any non-contiguous view triggers it —[::2]and[::-1]alike.The underlying problem is a use-after-free. For non-contiguous input,
get_data_from_buffer()releases the original view and makes a temporary contiguous copy, sobufpoints into memory owned byview.unpackb()then releasesviewin itsfinallyblock — freeing that copy — and only afterwards readsbuf+offto build theExtraDatapayload.That it is really freed memory, and not just an off-by-one, is easy to show with the macOS allocator's free-poisoning:
So arbitrary heap contents can end up in
ExtraData.extra. Thememcpy-param-overlapASan reports is the same event seen from the other side:PyBytes_FromStringAndSizere-allocates the just-freed block and copies it onto itself.Unpacker.feed()uses the same helper but copies viaappend_buffer()before releasing, so it is unaffected.One more data point: msgpack 1.1.1 does not silently corrupt on this input — it raises
SystemError: <class 'msgpack.exceptions.ExtraData'> returned a result with an exception set(from aBufferError), presumably a different symptom of the pre-#677 buffer handling. So the silent corruption looks specific to 1.2.x; the #677 fix did not cover this path.Fix plus a regression test: #722
ThomasWaldmann commentedon Aug 3, 2026
^ made with Claude Opus 5, carefully review please.
fix: use-after-free in unpackb() ExtraData path for non-contiguous in…