Skip to content

Commit 15cea32

Browse files
fix(capi): reject null and atom objects in raw vector readers (#21)
Co-authored-by: Evgen Byelozorov <belowzeroff@gmail.com>
1 parent f4327d3 commit 15cea32

2 files changed

Lines changed: 29 additions & 1 deletion

File tree

rayforce/capi/raypy_serde.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ PyObject *raypy_read_u8_vector(PyObject *self, PyObject *args) {
4949
if (!PyArg_ParseTuple(args, "O!", &RayObjectType, &obj))
5050
return NULL;
5151

52-
if (obj->obj->type != RAY_U8) {
52+
if (obj->obj == NULL || obj->obj->type != RAY_U8 || !ray_is_vec(obj->obj)) {
5353
PyErr_SetString(PyExc_RuntimeError, "read: object is not a u8 vector");
5454
return NULL;
5555
}
@@ -65,6 +65,12 @@ PyObject *raypy_read_vector_raw(PyObject *self, PyObject *args) {
6565
if (!PyArg_ParseTuple(args, "O!", &RayObjectType, &obj))
6666
return NULL;
6767

68+
/* Atoms alias `len` with their payload, so only true vecs are readable. */
69+
if (obj->obj == NULL || !ray_is_vec(obj->obj)) {
70+
PyErr_SetString(PyExc_RuntimeError, "read_vector_raw: object is not a vector");
71+
return NULL;
72+
}
73+
6874
size_t elem_size = ray_scalar_elem_size(obj->obj->type);
6975
if (elem_size == 0) {
7076
PyErr_SetString(PyExc_RuntimeError,

tests/ffi/test_init_read.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -370,3 +370,25 @@ def test_large_list_stress():
370370
# Spot-check first and last.
371371
assert FFI.read_i64(FFI.at_idx(lst, 0)) == 0
372372
assert FFI.read_i64(FFI.at_idx(lst, count - 1)) == count - 1
373+
374+
375+
def test_read_vector_raw_rejects_non_vectors():
376+
"""Regression: read_vector_raw / read_u8_vector used to dereference the
377+
underlying pointer without checks, so a bare RayObject() (obj == NULL)
378+
segfaulted the interpreter and an atom read garbage length bytes."""
379+
with pytest.raises(RuntimeError, match="not a vector"):
380+
r.read_vector_raw(r.RayObject())
381+
382+
with pytest.raises(RuntimeError, match="not a u8 vector"):
383+
r.read_u8_vector(r.RayObject())
384+
385+
# Atoms alias `len` with their payload — must be rejected, not read.
386+
with pytest.raises(RuntimeError, match="not a vector"):
387+
r.read_vector_raw(FFI.init_i64(5))
388+
389+
with pytest.raises(RuntimeError, match="not a u8 vector"):
390+
r.read_u8_vector(FFI.init_u8(5))
391+
392+
# Real vectors still read fine.
393+
vec = FFI.init_vector(r.TYPE_I64, [1, 2, 3])
394+
assert len(FFI.read_vector_raw(vec)) == 3 * 8

0 commit comments

Comments
 (0)