Skip to content

fix(prmi-sys): accept canonical NULL+0 arenas in backward-spectrum batch FFI - #51

Merged
nh13 merged 1 commit into
mainfrom
fix/backward-batch-null-zero
Jun 22, 2026
Merged

fix(prmi-sys): accept canonical NULL+0 arenas in backward-spectrum batch FFI#51
nh13 merged 1 commit into
mainfrom
fix/backward-batch-null-zero

Conversation

@nh13

@nh13 nh13 commented Jun 21, 2026

Copy link
Copy Markdown

What

The prmi-sys coding guideline requires every extern "C" entrypoint to handle the canonical empty-slice case NULL + len 0 — a C caller's conventional way to pass an empty buffer — without calling slice::from_raw_parts(NULL, 0), which is UB. The empty slice must be built directly.

The backward-spectrum batch entrypoints (prmi_backward_spectrum_batch, prmi_backward_spectrum_batch_lockstep) did not honor this: they rejected a NULL arena with a hard -1 whenever ntasks > 0, even when the arena's declared length was 0.

Changes

  • Split the null gate in backward_spectrum_batch_impl: tasks / out_nsteps (length ntasks) stay required, while reads_arena / steps_arena are rejected only when their declared length is non-zero.
  • Branch per-task slices to &[] / &mut [] for zero-length read/step windows, so a NULL + 0 arena is never passed to from_raw_parts. write_bwd_task_steps returns early on empty steps.
  • A NULL arena with a non-zero declared length is still a hard -1.
  • Gave prmi_backward_spectrum_batch_lockstep an explicit, self-contained return-code table (it previously deferred to the serial entrypoint), and updated the serial entrypoint's -1 description to document the NULL+0 acceptance.

Testing

New backward_spectrum_batch_accepts_null_plus_zero_arenas FFI regression test exercises both the serial and lockstep entrypoints with ntasks > 0, all-empty tasks, and NULL + 0 arenas (asserts rc == 0, out_nsteps == [0, 0], no NULL deref), plus the still-rejected NULL-with-nonzero-length case. clippy clean; full prmi-sys suite passes.

Relationship to #50

This is the backward-batch sibling of the forward-batch NULL + 0 hardening in #50. The two paths are independent code, so this is a standalone PR off main rather than part of #50.

Summary by CodeRabbit

  • Bug Fixes

    • Fixed undefined behavior when processing empty input data in batch operations to prevent potential crashes.
    • Improved null-pointer validation to safely handle edge cases with empty slices.
    • Enhanced error detection for invalid parameter combinations.
  • Tests

    • Added regression tests validating proper handling of empty inputs across different execution paths.

@coderabbitai

coderabbitai Bot commented Jun 21, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 9304f1f0-ad1f-418a-9e0a-9ec31133a26e

📥 Commits

Reviewing files that changed from the base of the PR and between 44b8b19 and e678ad2.

📒 Files selected for processing (2)
  • prmi-sys/src/lib.rs
  • prmi-sys/tests/spectrum_ffi.rs

Walkthrough

Tightens null-pointer validation in the backward batch FFI shim to accept NULL + 0 as a canonical empty slice for reads_arena and steps_arena. Both execution paths (lockstep and serial) gain per-task empty-slice guards, write_bwd_task_steps early-exits on empty output, and the public doc contracts are updated to match, with a new regression test.

Changes

NULL+0 arena safety for backward batch

Layer / File(s) Summary
Null validation and safe empty-slice construction
prmi-sys/src/lib.rs
Null validation in backward_spectrum_batch_impl rejects arena pointers only when declared length is non-zero. Per-task slice construction in both lockstep and serial paths substitutes &[]/&mut [] when lengths are zero without dereferencing arena pointers. write_bwd_task_steps returns early when steps is empty.
Documentation and regression test
prmi-sys/src/lib.rs, prmi-sys/tests/spectrum_ffi.rs
Doc comments for both public batch entrypoints explicitly document the NULL + 0 acceptance contract. New test backward_spectrum_batch_accepts_null_plus_zero_arenas exercises the happy path and asserts -1 for asymmetric NULL+nonzero-length cases.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately and concisely describes the main change: accepting canonical NULL+0 arenas in the backward-spectrum batch FFI, which is the core fix across both implementation and test additions.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/backward-batch-null-zero

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

…tch FFI

The `prmi-sys` coding guideline requires every C ABI entrypoint to handle the
canonical empty-slice case `NULL + len 0` (a C caller's conventional empty
buffer) without `slice::from_raw_parts(NULL, 0)`, which is UB — the empty slice
must be built directly. The backward-spectrum batch entrypoints did not: they
rejected a NULL arena with a hard `-1` whenever `ntasks > 0`, even when the
arena's declared length was 0.

Split the null gate so `tasks` / `out_nsteps` (length `ntasks`) stay required
while `reads_arena` / `steps_arena` are rejected only when their declared length
is non-zero, and branch the per-task read/step slices to `&[]` / `&mut []` for
zero-length windows (`write_bwd_task_steps` returns early on empty steps). A NULL
arena with a non-zero declared length is still a hard `-1`.

Also give `prmi_backward_spectrum_batch_lockstep` an explicit, self-contained
return-code table (it previously deferred to the serial entrypoint), and update
the serial entrypoint's `-1` description to document the NULL+0 acceptance.

Covered by a new backward NULL+0 FFI regression test over both the serial and
lockstep entrypoints, including the still-rejected NULL-with-nonzero-length case.
@nh13
nh13 force-pushed the fix/backward-batch-null-zero branch from 243f1c4 to e678ad2 Compare June 21, 2026 20:02
@nh13

nh13 commented Jun 22, 2026

Copy link
Copy Markdown
Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 22, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@nh13

nh13 commented Jun 22, 2026

Copy link
Copy Markdown
Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 22, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@nh13
nh13 merged commit f7eda69 into main Jun 22, 2026
4 checks passed
@nh13
nh13 deleted the fix/backward-batch-null-zero branch June 22, 2026 15:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant