Summary
The Rust test command in CONTRIBUTING.md does not match what CI runs. Following it as written segfaults, because rustpython-capi cannot be built correctly from the workspace root.
What happens
On Linux at ede18e44c:
| Command |
Result |
cargo test --workspace --exclude rustpython_wasm --exclude rustpython-venvlauncher — as documented |
exit 101, SIGSEGV |
the same plus --exclude rustpython-capi |
exit 0 — 1093 tests pass (1073 across 22 test binaries, plus 20 doc-tests) |
cd crates/capi && cargo test |
exit 0 — 102 passed |
This is not a stale-checkout or wrong-Python problem: CI is green on the same commit, and the workspace-root run still segfaults with python3 at 3.14.6.
thread 'abstract_::iter::tests::next_item' panicked at
pyo3-ffi-0.29.0/src/cpython/listobject.rs:33:5: null pointer dereference occurred
thread caused non-unwinding panic. aborting.
Which test dies varies with thread scheduling — whichever list-touching test runs first.
Why
crates/capi/.cargo/config.toml sets PYO3_CONFIG_FILE to pyo3-rustpython.config, which declares implementation=RustPython. pyo3 emits cargo:rustc-cfg=RustPython for that, which compiles out the struct-poking fast paths:
// pyo3-ffi/src/lib.rs
#[cfg(not(any(Py_LIMITED_API, RustPython)))]
mod cpython;
But per the Cargo Book, "when invoked from a workspace root, Cargo does not read config files from crates within the workspace." So from the root that config is skipped, mod cpython is compiled, and PyList::new dereferences PyListObject.ob_item on a RustPython object.
CI sidesteps this in two places — --exclude rustpython-capi on the workspace run, and working-directory: crates/capi on the separate c-api step. CONTRIBUTING.md does neither, and it is the first command a new contributor runs.
Possible fixes
- Update
CONTRIBUTING.md to mirror CI — add --exclude rustpython-capi and document the separate cd crates/capi && cargo test step.
- Give
crates/capi its own [workspace], or set root default-members, so --workspace never picks it up and the documented command works unchanged.
- Something else that makes the root invocation safe.
Drafted with AI assistance (Claude Code) and reviewed by me before posting.
Summary
The Rust test command in
CONTRIBUTING.mddoes not match what CI runs. Following it as written segfaults, becauserustpython-capicannot be built correctly from the workspace root.What happens
On Linux at
ede18e44c:cargo test --workspace --exclude rustpython_wasm --exclude rustpython-venvlauncher— as documentedSIGSEGV--exclude rustpython-capicd crates/capi && cargo testThis is not a stale-checkout or wrong-Python problem: CI is green on the same commit, and the workspace-root run still segfaults with
python3at 3.14.6.Which test dies varies with thread scheduling — whichever list-touching test runs first.
Why
crates/capi/.cargo/config.tomlsetsPYO3_CONFIG_FILEtopyo3-rustpython.config, which declaresimplementation=RustPython. pyo3 emitscargo:rustc-cfg=RustPythonfor that, which compiles out the struct-poking fast paths:But per the Cargo Book, "when invoked from a workspace root, Cargo does not read config files from crates within the workspace." So from the root that config is skipped,
mod cpythonis compiled, andPyList::newdereferencesPyListObject.ob_itemon a RustPython object.CI sidesteps this in two places —
--exclude rustpython-capion the workspace run, andworking-directory: crates/capion the separate c-api step.CONTRIBUTING.mddoes neither, and it is the first command a new contributor runs.Possible fixes
CONTRIBUTING.mdto mirror CI — add--exclude rustpython-capiand document the separatecd crates/capi && cargo teststep.crates/capiits own[workspace], or set rootdefault-members, so--workspacenever picks it up and the documented command works unchanged.Drafted with AI assistance (Claude Code) and reviewed by me before posting.