Skip to content

Commit d362c5f

Browse files
wan9chiclaude
andcommitted
refactor(fspy-shared): make the channel allocator-generic
channel(), Receiver, and sender() are now generic over an allocator-api2 allocator instead of hardcoding the global allocator and an internal pooled bump: - channel() threads the caller's allocator through the shared-memory backing path and the ShmKeeper; the supervisor instantiates with Global. - sender() takes the allocator for its transient shm-path decode from the caller, and the client constructors pass it through from the top of the call stack — the preload ctor and DllMain — so the choice of preload-safe memory lives where the attach begins, not inside library code. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent 6144412 commit d362c5f

12 files changed

Lines changed: 80 additions & 54 deletions

File tree

Cargo.lock

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/fspy/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ license.workspace = true
66
publish = false
77

88
[dependencies]
9+
allocator-api2 = { workspace = true, features = ["alloc"] }
910
wincode = { workspace = true }
1011
bstr = { workspace = true, features = ["alloc", "std"] }
1112
bumpalo = { workspace = true }

crates/fspy/src/ipc.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use allocator_api2::alloc::Global;
12
use fspy_shared::ipc::{
23
PathAccess,
34
channel::{FrameReader, Receiver},
@@ -37,7 +38,7 @@ pub struct ChannelAccesses {
3738
frames: FrameReader,
3839
}
3940

40-
impl TryFrom<Receiver> for ChannelAccesses {
41+
impl TryFrom<Receiver<Global>> for ChannelAccesses {
4142
type Error = TrackingIncomplete;
4243

4344
/// Closes the channel and takes every record it collected.
@@ -52,7 +53,7 @@ impl TryFrom<Receiver> for ChannelAccesses {
5253
/// [`TrackingIncomplete`] when a tracked process could not record
5354
/// something it went on to do. What did arrive is then a subset of
5455
/// what the run really touched, so none of it is handed back.
55-
fn try_from(receiver: Receiver) -> Result<Self, TrackingIncomplete> {
56+
fn try_from(receiver: Receiver<Global>) -> Result<Self, TrackingIncomplete> {
5657
Ok(Self { frames: receiver.close().map_err(|_| TrackingIncomplete)? })
5758
}
5859
}

crates/fspy/src/unix/mod.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,8 @@ impl SpyImpl {
8080

8181
#[cfg(not(target_env = "musl"))]
8282
let (ipc_channel_conf, ipc_receiver) =
83-
channel(crate::ipc::shm_capacity()).map_err(SpawnError::ChannelCreation)?;
83+
channel(crate::ipc::shm_capacity(), allocator_api2::alloc::Global)
84+
.map_err(SpawnError::ChannelCreation)?;
8485

8586
let payload = Payload {
8687
#[cfg(not(target_env = "musl"))]

crates/fspy/src/windows/mod.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,8 @@ impl SpyImpl {
8484
command.creation_flags(CREATE_SUSPENDED);
8585

8686
let (channel_conf, receiver) =
87-
channel(crate::ipc::shm_capacity()).map_err(SpawnError::ChannelCreation)?;
87+
channel(crate::ipc::shm_capacity(), allocator_api2::alloc::Global)
88+
.map_err(SpawnError::ChannelCreation)?;
8889

8990
let mut spawn_success = false;
9091
let spawn_success = &mut spawn_success;

crates/fspy_client_unix/src/lib.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ pub mod raw_exec;
1010

1111
use std::{ffi::OsStr, fmt::Debug, os::unix::ffi::OsStrExt as _, path::Path};
1212

13+
use allocator_api2::alloc::Allocator;
1314
use convert::{ToAbsolutePath, ToAccessMode};
1415
use fspy_shared::ipc::{PathAccess, channel::Sender};
1516
use fspy_shared_unix::{
@@ -47,14 +48,17 @@ impl Client {
4748
/// Panics when the payload is missing, malformed, or cannot be decoded,
4849
/// and when the channel is there but cannot be attached to (see
4950
/// [`ChannelConf::sender`](fspy_shared::ipc::channel::ChannelConf::sender)).
50-
pub fn from_env(envs: impl Iterator<Item = fspy_nostd::env::Entry>) -> Self {
51+
pub fn from_env(
52+
envs: impl Iterator<Item = fspy_nostd::env::Entry>,
53+
allocator: impl Allocator,
54+
) -> Self {
5155
let encoded_payload = decode_payload_from_env(envs).unwrap();
5256

5357
// `None` when the channel is already over, which happens when this
5458
// process starts after the root target exited. Nothing is said
5559
// about it: a preload library writing to the traced process's
5660
// stderr corrupts whatever that process is printing.
57-
let ipc_sender = encoded_payload.payload.ipc_channel_conf.sender();
61+
let ipc_sender = encoded_payload.payload.ipc_channel_conf.sender(allocator);
5862

5963
Self { encoded_payload, ipc_sender }
6064
}

crates/fspy_preload_unix/src/client.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,5 +45,5 @@ fn init_client() {
4545
// SAFETY: the ctor only reads the process environment while constructing
4646
// the client and does not retain borrowed environment views.
4747
let current = unsafe { fspy_nostd::env::current() }.unwrap();
48-
CLIENT.set(Client::from_env(current.envs())).unwrap();
48+
CLIENT.set(Client::from_env(current.envs(), fspy_nostd_alloc::pooled_bump())).unwrap();
4949
}

crates/fspy_preload_windows/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ wincode = { workspace = true }
1313
constcat = { workspace = true }
1414
fspy_detours_sys = { workspace = true }
1515
fspy_nostd = { workspace = true }
16+
allocator-api2 = { workspace = true }
17+
fspy_nostd_alloc = { workspace = true }
1618
fspy_shared = { workspace = true }
1719
ntapi = { workspace = true }
1820
smallvec = { workspace = true }

crates/fspy_preload_windows/src/windows/client.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use std::{cell::SyncUnsafeCell, ffi::CStr, mem::MaybeUninit};
22

3+
use allocator_api2::alloc::Allocator;
34
use fspy_detours_sys::DetourCopyPayloadToProcess;
45
use fspy_shared::{
56
ipc::{PathAccess, channel::Sender},
@@ -13,14 +14,14 @@ pub struct Client<'a> {
1314
}
1415

1516
impl<'a> Client<'a> {
16-
pub fn from_payload_bytes(payload_bytes: &'a [u8]) -> Self {
17+
pub fn from_payload_bytes(payload_bytes: &'a [u8], allocator: impl Allocator) -> Self {
1718
let payload: Payload<'a> = wincode::deserialize_exact(payload_bytes).unwrap();
1819

1920
// `None` when the channel is already over, which happens when this
2021
// process starts after the root target exited. Nothing is said
2122
// about it: a detours DLL writing to the traced process's stderr
2223
// corrupts whatever that process is printing.
23-
let ipc_sender = payload.channel_conf.sender();
24+
let ipc_sender = payload.channel_conf.sender(allocator);
2425

2526
Self { payload, ipc_sender }
2627
}

crates/fspy_preload_windows/src/windows/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ fn dll_main(_hinstance: HINSTANCE, reason: u32) -> winsafe::SysResult<()> {
4545
let payload_bytes = unsafe {
4646
slice::from_raw_parts::<'static, u8>(payload_ptr, payload_len.try_into().unwrap())
4747
};
48-
let client = Client::from_payload_bytes(payload_bytes);
48+
let client = Client::from_payload_bytes(payload_bytes, fspy_nostd_alloc::pooled_bump());
4949
// SAFETY: setting the global client during single-threaded DLL_PROCESS_ATTACH
5050
unsafe { set_global_client(client) };
5151

0 commit comments

Comments
 (0)