fix(capi): reject null and atom objects in raw vector readers - #21
Merged
protocolstardust merged 2 commits intoJul 24, 2026
Merged
Conversation
read_vector_raw / read_u8_vector dereferenced the wrapped pointer without checks: a bare RayObject() (obj == NULL) segfaulted the interpreter, and an atom passed to read_vector_raw read a garbage length because atoms alias len with their payload. Both now raise RuntimeError like the other readers.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Two C readers dereference the wrapped
ray_t*without any validation, so they can crash the interpreter from pure Python:read_u8_vectorhas the same uncheckedobj->obj->typeaccess. A second, subtler case: passing an atom toread_vector_rawpasses theray_scalar_elem_sizecheck (it takesabs(type)), but atoms aliaslenwith their payload, so the reader fabricates a garbage byte length forPyBytes_FromStringAndSize— an out-of-bounds read of arbitrary size.RayObjectis constructible from Python (tp_new = PyType_GenericNew, and the.pyistub declares__init__), so nothing prevents these calls; every other reader in the binding already guards viacheck_type/unwrap_vec.Fix
Bring the two stragglers in line with the rest of the binding:
read_vector_raw: reject NULL and non-vector objects (ray_is_vec) withRuntimeErrorbefore touchingtype/len.read_u8_vector: fold the NULL check into the existing type check.No behavior change for valid inputs — all existing callers (
Vector.to_list/to_numpy/__getitem__,F32.to_python, IPC/WS send paths) pass real vectors.Tests
test_read_vector_raw_rejects_non_vectors— bareRayObject()and ani64atom now raiseRuntimeErrorfor both readers, and a real vector still round-trips (3 * 8bytes). The test segfaults the interpreter on master.Full suite: 2328 passed, 7 skipped (macOS arm64, core 2.5.0, extension rebuilt from this branch).