Skip to content

Commit 728413c

Browse files
branchseerclaude
andauthored
refactor(fspy): gate ipc channel module on non-musl targets (#328)
## Summary Gate the entire `fspy_shared::ipc::channel` module behind `#[cfg(not(target_env = "musl"))]`. The shared-memory IPC channel exists to move path accesses from the preload library to the supervisor, but on musl targets the preload library isn't built (seccomp-only tracking is used). With no senders, the channel produces no data, and creating it on musl just wastes a 4 GiB shared-memory region, a lock file, and a blocking receiver-lock step after the child exits. ### Changes - `fspy_shared::ipc::channel` module is now non-musl only - `fspy::ipc` (re-exports `OwnedReceiverLockGuard`, `SHM_CAPACITY`) is non-musl only - `fspy::unix::SpyImpl::spawn` skips channel creation on musl - `PathAccessIterable` drops its `ipc_receiver_lock_guard` field on musl; `iter()` only yields arena-collected accesses there - Fixed latent issue exposed by this PR: `Payload::seccomp_payload`'s `struct_field_names` `#[expect]` is now `#[cfg_attr(not(target_env = "musl"), ...)]` since on musl `Payload` has only this one field and clippy's `struct_field_names` lint no longer fires Windows paths are untouched — they never satisfy `target_env = "musl"`. ## Test plan - [x] `cargo check --workspace --all-features` on host (glibc) - [x] `cargo check --workspace --all-features --target x86_64-unknown-linux-musl` - [x] `cargo clippy --workspace --all-targets --all-features -- -D warnings` on host - [x] `cargo fmt --check` - [x] `RUSTDOCFLAGS='-D warnings' cargo doc --no-deps --document-private-items` - [x] `cargo test -p fspy_shared -p fspy_shared_unix` (24 pass) - [x] `cargo test -p fspy --test node_fs` — exercises the full spawn + IPC pipeline (8 pass) https://claude.ai/code/session_01VqiMHiGeViu1pGhWwJ67Qc Co-authored-by: Claude <noreply@anthropic.com>
1 parent 2f1e32b commit 728413c

File tree

4 files changed

+27
-14
lines changed

4 files changed

+27
-14
lines changed

crates/fspy/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ mod artifact;
88

99
pub mod error;
1010

11+
#[cfg(not(target_env = "musl"))]
1112
mod ipc;
1213

1314
#[cfg(unix)]

crates/fspy/src/unix/mod.rs

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@ use std::{io, path::Path};
88

99
#[cfg(target_os = "linux")]
1010
use fspy_seccomp_unotify::supervisor::supervise;
11+
use fspy_shared::ipc::PathAccess;
1112
#[cfg(not(target_env = "musl"))]
12-
use fspy_shared::ipc::NativeStr;
13-
use fspy_shared::ipc::{PathAccess, channel::channel};
13+
use fspy_shared::ipc::{NativeStr, channel::channel};
1414
#[cfg(target_os = "macos")]
1515
use fspy_shared_unix::payload::Artifacts;
1616
use fspy_shared_unix::{
@@ -24,12 +24,9 @@ use syscall_handler::SyscallHandler;
2424
use tokio::task::spawn_blocking;
2525
use tokio_util::sync::CancellationToken;
2626

27-
use crate::{
28-
ChildTermination, Command, TrackedChild,
29-
arena::PathAccessArena,
30-
error::SpawnError,
31-
ipc::{OwnedReceiverLockGuard, SHM_CAPACITY},
32-
};
27+
#[cfg(not(target_env = "musl"))]
28+
use crate::ipc::{OwnedReceiverLockGuard, SHM_CAPACITY};
29+
use crate::{ChildTermination, Command, TrackedChild, arena::PathAccessArena, error::SpawnError};
3330

3431
#[derive(Debug)]
3532
pub struct SpyImpl {
@@ -92,8 +89,6 @@ impl SpyImpl {
9289
#[cfg(not(target_env = "musl"))]
9390
let (ipc_channel_conf, ipc_receiver) =
9491
channel(SHM_CAPACITY).map_err(SpawnError::ChannelCreation)?;
95-
#[cfg(target_env = "musl")]
96-
let (_, ipc_receiver) = channel(SHM_CAPACITY).map_err(SpawnError::ChannelCreation)?;
9792

9893
let payload = Payload {
9994
#[cfg(not(target_env = "musl"))]
@@ -174,9 +169,14 @@ impl SpyImpl {
174169

175170
// Lock the ipc channel after the child has exited.
176171
// We are not interested in path accesses from descendants after the main child has exited.
172+
#[cfg(not(target_env = "musl"))]
177173
let ipc_receiver_lock_guard =
178174
OwnedReceiverLockGuard::lock_async(ipc_receiver).await?;
179-
let path_accesses = PathAccessIterable { arenas, ipc_receiver_lock_guard };
175+
let path_accesses = PathAccessIterable {
176+
arenas,
177+
#[cfg(not(target_env = "musl"))]
178+
ipc_receiver_lock_guard,
179+
};
180180

181181
io::Result::Ok(ChildTermination { status, path_accesses })
182182
})
@@ -188,6 +188,7 @@ impl SpyImpl {
188188

189189
pub struct PathAccessIterable {
190190
arenas: Vec<PathAccessArena>,
191+
#[cfg(not(target_env = "musl"))]
191192
ipc_receiver_lock_guard: OwnedReceiverLockGuard,
192193
}
193194

@@ -196,7 +197,14 @@ impl PathAccessIterable {
196197
let accesses_in_arena =
197198
self.arenas.iter().flat_map(|arena| arena.borrow_accesses().iter()).copied();
198199

199-
let accesses_in_shm = self.ipc_receiver_lock_guard.iter_path_accesses();
200-
accesses_in_shm.chain(accesses_in_arena)
200+
#[cfg(not(target_env = "musl"))]
201+
{
202+
let accesses_in_shm = self.ipc_receiver_lock_guard.iter_path_accesses();
203+
accesses_in_shm.chain(accesses_in_arena)
204+
}
205+
#[cfg(target_env = "musl")]
206+
{
207+
accesses_in_arena
208+
}
201209
}
202210
}

crates/fspy_shared/src/ipc/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#[cfg(not(target_env = "musl"))]
12
pub mod channel;
23
mod native_path;
34
pub(crate) mod native_str;

crates/fspy_shared_unix/src/payload.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,10 @@ pub struct Payload {
2020
pub artifacts: Artifacts,
2121

2222
#[cfg(target_os = "linux")]
23-
#[expect(clippy::struct_field_names, reason = "descriptive field name for clarity")]
23+
#[cfg_attr(
24+
not(target_env = "musl"),
25+
expect(clippy::struct_field_names, reason = "descriptive field name for clarity")
26+
)]
2427
pub seccomp_payload: fspy_seccomp_unotify::payload::SeccompPayload,
2528
}
2629

0 commit comments

Comments
 (0)