Skip to content

fix(rvf-runtime,rvlite): read errno portably so every Unix target compiles - #757

Open
ohdearquant wants to merge 1 commit into
ruvnet:mainfrom
ohdearquant:fix/errno-portability
Open

fix(rvf-runtime,rvlite): read errno portably so every Unix target compiles#757
ohdearquant wants to merge 1 commit into
ruvnet:mainfrom
ohdearquant:fix/errno-portability

Conversation

@ohdearquant

@ohdearquant ohdearquant commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

The defect

is_pid_alive is compiled under #[cfg(unix)], but the errno accessor it calls is defined only
for linux, android, macos, ios and freebsd. On any other Unix the caller is compiled and
the callee is not:

$ cargo check -p rvf-runtime --target x86_64-unknown-netbsd
error[E0425]: cannot find function `libc_errno` in this scope
   --> crates/rvf/rvf-runtime/src/locking.rs:283:29
    |
283 |         let err = unsafe { *libc_errno() };
    |                             ^^^^^^^^^^ not found in this scope

crates/rvlite/src/storage/writer_lease.rs carries the same shape, reachable with
--features rvf-backend.

This is adjacent to #746 but not the same defect. #746's symptom, the missing __error on macOS, is
already fixed on main and in the published 0.3.2 — I checked the shipped source rather than the
version number, and 0.3.2 went out on 2026-07-28, two days before that issue was filed. What the fix
left behind is narrower and quieter: the trigger condition is all of unix, the reach is a fixed
list of five, and the targets in the gap moved from a link error to a compile error.

Why not just add the missing targets

Extending the list works until the next target. NetBSD and OpenBSD use __errno, DragonFly uses
__dfly_error, Solaris and illumos use ___errno, and each one has to be right. The list is a
restatement of libc internals that has to be maintained against platforms nobody here builds on,
which is how it drifted the first time.

std::io::Error::last_os_error() reads errno through each platform's own accessor. It covers every
Unix without naming a symbol, needs no new dependency, and removes two unsafe blocks and four
extern declarations. The EPERM comparison is unchanged, so the behaviour is the same on the
platforms that already worked.

Verification

arm before after
check -p rvf-runtime --target x86_64-unknown-netbsd error[E0425] clean
check -p rvlite --features rvf-backend --target x86_64-unknown-netbsd error[E0425] clean
check -p rvf-runtime --target x86_64-unknown-linux-gnu clean clean
check -p rvlite --features rvf-backend (host, macOS) clean clean
test -p rvf-runtime --lib 243 passed, 0 failed
test -p rvlite --features rvf-backend --lib 118 passed, 0 failed
fmt --all --check clean clean
clippy --workspace --all-targets --no-deps -- -D warnings 1 pre-existing error in ruvector-solver same 1, unchanged

The clippy row is a comparison against the base tree with the same command, so the pre-existing
error is stated rather than silently inherited. This change neither adds nor fixes it.

About the added test

rvlite's is_pid_alive had no coverage. Replacing its errno comparison with a constant true
left the whole suite green at 117 passed, which means nothing in it observed that line. The added
test fails under that mutation and passes with the fix, so it holds the behaviour rather than
decorating it. rvf-runtime needed no new test: the same mutation there already fails
locking::tests::stale_lock_detection.

Why this survived

Neither path is reachable by the workspace CI as configured, which is worth knowing independently of
this patch:

  • rvf-runtime is not a workspace member, so cargo clippy --workspace and cargo test --workspace
    never reach it. cargo test -p rvf-runtime from the workspace root reports that it "requires
    dev-dependencies and is not a member of the workspace".
  • rvlite's writer_lease module is behind #[cfg(feature = "rvf-backend")] and rvlite defaults
    to default = [], so a default build compiles it out. I confirmed that by putting a
    compile_error! in the file and watching a default-feature check still succeed.

Both are cheap to close if you want them closed, and I'm happy to open that separately rather than
widen this PR.

One more limitation, on the test itself

A later review pass of my own turned up a gap worth stating rather than leaving for you to find:
the added test does not guard the thing this PR fixes. It exercises the runtime ESRCH
behaviour, and it would still pass on Linux and macOS if the previous target-gated errno accessors
were restored, because those targets were never the broken ones. The defect this PR closes is a
compilation failure on Unix targets outside that gated set, and no test here can observe that
from a host build.

What would actually guard it is a CI cargo check against one uncovered Unix target — for example
x86_64-unknown-netbsd. I have not added that, because it needs a cross toolchain in CI and that
is a change to your build infrastructure rather than to this crate, so it seemed like your call
rather than mine. Happy to open it separately if you want it.

To be precise about the strength of the claim: I verified the reasoning above by reading the diff
and the two changed files, not by executing a build against an uncovered target. So "would still
pass with the old code restored" is a reasoned conclusion, not a measured one.


Note on this PR's CI. Tests (core-and-rest) is red on every branch in this repository,
including main: the job is cancelled at its 240-minute cap while still compiling and never
reaches the test phase. #786 restores the exclusion list that the shard's packages: value loses
to a shell comment, #784 unblocks the ruvector-filter test target that the compiler cannot
finish, and #787 fixes a deadlock waiting behind both. That failure is not caused by this branch.

…piles

is_pid_alive runs under #[cfg(unix)] but the errno accessor it calls was defined
only for linux, android, macos, ios and freebsd. On any other Unix the caller is
compiled and the callee is not, so the build fails to resolve it:

    error[E0425]: cannot find function `libc_errno` in this scope
       --> crates/rvf/rvf-runtime/src/locking.rs:283:29

Reproduced with cargo check -p rvf-runtime --target x86_64-unknown-netbsd, and
via rvlite with --features rvf-backend, which reaches the same shape in
storage/writer_lease.rs. Extending the per-OS symbol list would leave the same
gap open for the next target, since the trigger condition is all of unix while
the hand-declared reach is a fixed list.

std::io::Error::last_os_error() reads errno through each platform's own
accessor, so it covers every Unix without naming any symbol, needs no new
dependency, and removes two unsafe blocks and four extern declarations.

Adds a direct test for rvlite's is_pid_alive. Replacing the errno comparison
with a constant true left rvlite's suite fully green, so that line had no
coverage; the new test fails under that mutation and passes with the fix.
rvf-runtime already had coverage: the same mutation fails stale_lock_detection.
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