From 216061cefab54c9e1c514b6ed441b72c1ee44b18 Mon Sep 17 00:00:00 2001 From: usama khan Date: Thu, 8 Oct 2026 01:51:04 +0530 Subject: [PATCH] Reject non-contiguous memoryviews in pack_command The memoryview branch copied p_buf->len bytes from the base pointer of PyMemoryView_GET_BUFFER, which only spans the payload when the view is C-contiguous. A reversed or strided view puts buf at a different offset and carries its own strides, so the copy ran off the end of the underlying buffer and the out-of-bounds bytes were spliced into the packed command: packing memoryview(bytearray(b'.' * 32))[::-1] returned 15 bytes of the next heap allocation, and a 256 MiB bytearray segfaulted. Acquiring the view with PyObject_GetBuffer under PyBUF_SIMPLE rejects non-contiguous input with the same BufferError that Reader.feed already raises for it, and leaves contiguous memoryviews unchanged. --- src/pack.c | 13 ++++++++++--- tests/test_pack.py | 9 +++++++++ 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/pack.c b/src/pack.c index 23e4004..a904b9b 100644 --- a/src/pack.c +++ b/src/pack.c @@ -77,9 +77,16 @@ pack_command(PyObject *cmd) } else if (PyMemoryView_Check(item)) { - Py_buffer *p_buf = PyMemoryView_GET_BUFFER(item); - tokens[i] = sdsnewlen(p_buf->buf, p_buf->len); - lengths[i] = p_buf->len; + Py_buffer buffer; + if (PyObject_GetBuffer(item, &buffer, PyBUF_SIMPLE) == -1) + { + // PyObject_GetBuffer sets an exception. + goto cleanup; + } + + tokens[i] = sdsnewlen(buffer.buf, buffer.len); + lengths[i] = buffer.len; + PyBuffer_Release(&buffer); } else { diff --git a/tests/test_pack.py b/tests/test_pack.py index 2c3dbfd..be9d32f 100644 --- a/tests/test_pack.py +++ b/tests/test_pack.py @@ -45,3 +45,12 @@ def __init__(self) -> None: with pytest.raises(TypeError): hiredis.pack_command(("HSET", "foo", Bar())) + + +def test_non_contiguous_memoryview(): + # A reversed memoryview starts at the last byte of its buffer, so copying + # nbytes forward from it reads past the end of the bytearray. + view = memoryview(bytearray(b"0123456789abcdef"))[::-1] + + with pytest.raises(BufferError): + hiredis.pack_command(("SET", "a", view))