Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
200 changes: 117 additions & 83 deletions Cargo.lock

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ members = ["crates/*"]
authors = ["Vite+ Authors"]
edition = "2024"
license = "MIT"
rust-version = "1.88.0"
rust-version = "1.89.0"
Comment thread
branchseer marked this conversation as resolved.

[workspace.lints.rust]
absolute_paths_not_starting_with_crate = "warn"
Expand Down Expand Up @@ -44,7 +44,7 @@ assert2 = "0.3.16"
assertables = "9.8.1"
async-trait = "0.1.89"
base64 = "0.22.1"
bincode = "2.0.1"
wincode = "0.5.2"
bindgen = "0.72.1"
bitflags = "2.10.0"
# The newest released version (0.3.0) of brush-parser has a bug that reports incorrect locations for some ast nodes.
Expand Down
2 changes: 1 addition & 1 deletion crates/fspy/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ publish = false

[dependencies]
allocator-api2 = { workspace = true, features = ["alloc"] }
bincode = { workspace = true }
wincode = { workspace = true }
bstr = { workspace = true, default-features = false }
bumpalo = { workspace = true }
const_format = { workspace = true, features = ["fmt"] }
Expand Down
12 changes: 4 additions & 8 deletions crates/fspy/src/ipc.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
use std::io;

use bincode::borrow_decode_from_slice;
use fspy_shared::ipc::{
BINCODE_CONFIG, PathAccess,
PathAccess,
channel::{Receiver, ReceiverLockGuard},
};
use tokio::task::spawn_blocking;
Expand Down Expand Up @@ -32,11 +31,8 @@ impl OwnedReceiverLockGuard {
}

pub fn iter_path_accesses(&self) -> impl Iterator<Item = PathAccess<'_>> {
self.borrow_lock_guard().iter_frames().map(|frame| {
let (path_access, decoded_size) =
borrow_decode_from_slice::<PathAccess<'_>, _>(frame, BINCODE_CONFIG).unwrap();
assert_eq!(decoded_size, frame.len());
path_access
})
self.borrow_lock_guard()
.iter_frames()
.map(|frame| wincode::deserialize_exact(frame).unwrap())
}
}
4 changes: 2 additions & 2 deletions crates/fspy/src/windows/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use std::{
use const_format::formatcp;
use fspy_detours_sys::{DetourCopyPayloadToProcess, DetourUpdateProcessWithDll};
use fspy_shared::{
ipc::{BINCODE_CONFIG, PathAccess, channel::channel},
ipc::{PathAccess, channel::channel},
windows::{PAYLOAD_ID, Payload},
};
use futures_util::FutureExt;
Expand Down Expand Up @@ -109,7 +109,7 @@ impl SpyImpl {
channel_conf: channel_conf.clone(),
ansi_dll_path_with_nul: ansi_dll_path_with_nul.to_bytes(),
};
let payload_bytes = bincode::encode_to_vec(payload, BINCODE_CONFIG).unwrap();
let payload_bytes = wincode::serialize(&payload).unwrap();
// SAFETY: process_handle is valid, PAYLOAD_ID is a static GUID,
// payload_bytes is a valid buffer with correct length
let success = unsafe {
Expand Down
2 changes: 1 addition & 1 deletion crates/fspy_preload_unix/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ crate-type = ["cdylib"]

[target.'cfg(unix)'.dependencies]
anyhow = { workspace = true }
bincode = { workspace = true }
wincode = { workspace = true }
bstr = { workspace = true, default-features = false }
ctor = { workspace = true }
fspy_shared = { workspace = true }
Expand Down
15 changes: 8 additions & 7 deletions crates/fspy_preload_unix/src/client/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@ use std::{
sync::OnceLock,
};

use bincode::{enc::write::SizeWriter, encode_into_slice, encode_into_writer};
use convert::{ToAbsolutePath, ToAccessMode};
use fspy_shared::ipc::{BINCODE_CONFIG, PathAccess, channel::Sender};
use fspy_shared::ipc::{PathAccess, channel::Sender};
use fspy_shared_unix::{
exec::ExecResolveConfig,
payload::EncodedPayload,
spawn::{PreExec, handle_exec},
};
use raw_exec::RawExec;
use wincode::Serialize as _;

pub struct Client {
encoded_payload: EncodedPayload,
Expand Down Expand Up @@ -72,17 +72,18 @@ impl Client {
return Ok(());
}
let path_access = PathAccess { mode, path: path.into() };
let mut size_writer = SizeWriter::default();
encode_into_writer(path_access, &mut size_writer, BINCODE_CONFIG)?;
let serialized_size = usize::try_from(PathAccess::serialized_size(&path_access)?)
.expect("serialized size exceeds usize");

let frame_size = NonZeroUsize::new(size_writer.bytes_written)
let frame_size = NonZeroUsize::new(serialized_size)
.expect("fspy: encoded PathAccess should never be empty");

let mut frame = ipc_sender
.claim_frame(frame_size)
.expect("fspy: failed to claim frame in shared memory");
let written_size = encode_into_slice(path_access, &mut frame, BINCODE_CONFIG)?;
assert_eq!(written_size, size_writer.bytes_written);
let mut writer: &mut [u8] = &mut frame;
PathAccess::serialize_into(&mut writer, &path_access)?;
assert_eq!(writer.len(), 0);

Ok(())
}
Expand Down
2 changes: 1 addition & 1 deletion crates/fspy_preload_windows/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ edition.workspace = true
crate-type = ["cdylib"]

[target.'cfg(target_os = "windows")'.dependencies]
bincode = { workspace = true }
wincode = { workspace = true }
constcat = { workspace = true }
fspy_detours_sys = { workspace = true }
fspy_shared = { workspace = true }
Expand Down
11 changes: 4 additions & 7 deletions crates/fspy_preload_windows/src/windows/client.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
use std::{cell::SyncUnsafeCell, ffi::CStr, mem::MaybeUninit};

use bincode::{borrow_decode_from_slice, encode_to_vec};
use fspy_detours_sys::DetourCopyPayloadToProcess;
use fspy_shared::{
ipc::{BINCODE_CONFIG, PathAccess, channel::Sender},
ipc::{PathAccess, channel::Sender},
windows::{PAYLOAD_ID, Payload},
};
use winapi::{shared::minwindef::BOOL, um::winnt::HANDLE};
Expand All @@ -15,9 +14,7 @@ pub struct Client<'a> {

impl<'a> Client<'a> {
pub fn from_payload_bytes(payload_bytes: &'a [u8]) -> Self {
let (payload, decoded_len) =
borrow_decode_from_slice::<'a, Payload, _>(payload_bytes, BINCODE_CONFIG).unwrap();
assert_eq!(decoded_len, payload_bytes.len());
let payload: Payload<'a> = wincode::deserialize_exact(payload_bytes).unwrap();

let ipc_sender = match payload.channel_conf.sender() {
Ok(sender) => Some(sender),
Expand All @@ -43,11 +40,11 @@ impl<'a> Client<'a> {
let Some(sender) = &self.ipc_sender else {
return;
};
sender.write_encoded(&access, BINCODE_CONFIG).expect("failed to send path access");
sender.write_encoded(&access).expect("failed to send path access");
}

pub unsafe fn prepare_child_process(&self, child_handle: HANDLE) -> BOOL {
let payload_bytes = encode_to_vec(&self.payload, BINCODE_CONFIG).unwrap();
let payload_bytes = wincode::serialize(&self.payload).unwrap();
// SAFETY: FFI call to DetourCopyPayloadToProcess with valid handle and payload buffer
unsafe {
DetourCopyPayloadToProcess(
Expand Down
2 changes: 1 addition & 1 deletion crates/fspy_seccomp_unotify/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ edition = "2024"
publish = false

[target.'cfg(target_os = "linux")'.dependencies]
bincode = { workspace = true }
wincode = { workspace = true, features = ["derive"] }
libc = { workspace = true }
nix = { workspace = true, features = ["process", "fs", "poll", "socket", "uio"] }
passfd = { workspace = true, default-features = false, optional = true }
Expand Down
6 changes: 3 additions & 3 deletions crates/fspy_seccomp_unotify/src/payload/filter.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use bincode::{Decode, Encode};
use wincode::{SchemaRead, SchemaWrite};

#[derive(Debug, Encode, Decode, Clone, Copy)]
#[derive(Debug, SchemaWrite, SchemaRead, Clone, Copy)]
pub struct CodableSockFilter {
code: u16,
jt: u8,
Expand All @@ -24,5 +24,5 @@ impl From<CodableSockFilter> for libc::sock_filter {
}
}

#[derive(Encode, Decode, Debug, Clone)]
#[derive(SchemaWrite, SchemaRead, Debug, Clone)]
pub struct Filter(pub(crate) Vec<CodableSockFilter>);
4 changes: 2 additions & 2 deletions crates/fspy_seccomp_unotify/src/payload/mod.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
mod filter;
use bincode::{Decode, Encode};
pub use filter::Filter;
use wincode::{SchemaRead, SchemaWrite};

#[derive(Debug, Encode, Decode, Clone)]
#[derive(Debug, SchemaWrite, SchemaRead, Clone)]
pub struct SeccompPayload {
pub(crate) ipc_path: Vec<u8>,
pub(crate) filter: Filter,
Expand Down
2 changes: 1 addition & 1 deletion crates/fspy_shared/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ publish = false

[dependencies]
allocator-api2 = { workspace = true }
bincode = { workspace = true }
wincode = { workspace = true, features = ["derive"] }
bitflags = { workspace = true }
bstr = { workspace = true }
bytemuck = { workspace = true, features = ["must_cast", "derive"] }
Expand Down
39 changes: 36 additions & 3 deletions crates/fspy_shared/src/ipc/channel/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,54 @@

mod shm_io;

use std::{env::temp_dir, fs::File, io, ops::Deref, path::PathBuf, sync::Arc};
use std::{env::temp_dir, fs::File, io, mem::MaybeUninit, ops::Deref, path::PathBuf, sync::Arc};

use bincode::{Decode, Encode};
use shared_memory::{Shmem, ShmemConf};
pub use shm_io::FrameMut;
use shm_io::{ShmReader, ShmWriter};
use tracing::debug;
use uuid::Uuid;
use wincode::{
SchemaRead, SchemaWrite,
config::Config,
error::{ReadResult, WriteResult},
io::{Reader, Writer},
};

use super::NativeStr;

/// wincode schema adapter for `Arc<str>`, which is a foreign type with unsized inner.
pub(crate) struct ArcStrSchema;

// SAFETY: Delegates to `str`'s SchemaWrite impl, preserving its size/write invariants.
unsafe impl<C: Config> SchemaWrite<C> for ArcStrSchema {
type Src = Arc<str>;

fn size_of(src: &Self::Src) -> WriteResult<usize> {
<str as SchemaWrite<C>>::size_of(src)
}

fn write(writer: impl Writer, src: &Self::Src) -> WriteResult<()> {
<str as SchemaWrite<C>>::write(writer, src)
}
}

// SAFETY: Delegates to `&str`'s SchemaRead impl; dst is initialized on Ok.
unsafe impl<'de, C: Config> SchemaRead<'de, C> for ArcStrSchema {
type Dst = Arc<str>;

fn read(mut reader: impl Reader<'de>, dst: &mut MaybeUninit<Self::Dst>) -> ReadResult<()> {
let s: &str = <&str as SchemaRead<'de, C>>::get(&mut reader)?;
dst.write(Arc::from(s));
Ok(())
}
}

/// Serializable configuration to create channel senders.
#[derive(Encode, Decode, Clone, Debug)]
#[derive(SchemaWrite, SchemaRead, Clone, Debug)]
pub struct ChannelConf {
lock_file_path: Box<NativeStr>,
#[wincode(with = "ArcStrSchema")]
shm_id: Arc<str>,
shm_size: usize,
}
Expand Down
20 changes: 9 additions & 11 deletions crates/fspy_shared/src/ipc/channel/shm_io.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,9 @@ use std::{
sync::atomic::{AtomicI32, AtomicUsize, Ordering, fence},
};

use bincode::{
Encode, config::Config, enc::write::SizeWriter, encode_into_slice, encode_into_writer,
};
use bytemuck::must_cast;
use shared_memory::Shmem;
use wincode::{SchemaWrite, Serialize as _, config::DefaultConfig};

// `ShmWriter` writes headers using atomic operations to prevent partial writes due to crashes,
// while `ShmReader` reads headers by simple pointer dereferences.
Expand Down Expand Up @@ -109,7 +107,7 @@ impl Drop for FrameMut<'_> {
#[derive(thiserror::Error, Debug)]
pub enum WriteEncodedError {
#[error("Failed to encode value into shared memory")]
EncodeError(#[from] bincode::error::EncodeError),
EncodeError(#[from] wincode::error::WriteError),
#[error("Tried to write a frame of zero size into shared memory")]
ZeroSizedFrame,
#[error("Not enough space in shared memory to write the encoded frame")]
Expand Down Expand Up @@ -226,23 +224,23 @@ impl<M: AsRawSlice> ShmWriter<M> {
}

/// Append an encoded value into the shared memory.
pub fn write_encoded<T: Encode, C: Config>(
pub fn write_encoded<T: SchemaWrite<DefaultConfig, Src = T>>(
&self,
value: &T,
config: C,
) -> Result<(), WriteEncodedError> {
let mut size_writer = SizeWriter::default();
encode_into_writer(value, &mut size_writer, config)?;
let serialized_size =
usize::try_from(T::serialized_size(value)?).expect("serialized size exceeds usize");

let Some(frame_size) = NonZeroUsize::new(size_writer.bytes_written) else {
let Some(frame_size) = NonZeroUsize::new(serialized_size) else {
return Err(WriteEncodedError::ZeroSizedFrame);
};
let Some(mut frame) = self.claim_frame(frame_size) else {
return Err(WriteEncodedError::InsufficientSpace);
};

let written_size = encode_into_slice(value, &mut frame, config)?;
assert_eq!(written_size, size_writer.bytes_written);
let mut writer: &mut [u8] = &mut frame;
T::serialize_into(&mut writer, value)?;
assert_eq!(writer.len(), 0);

Ok(())
}
Expand Down
8 changes: 3 additions & 5 deletions crates/fspy_shared/src/ipc/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,12 @@ pub(crate) mod native_str;

use std::fmt::Debug;

use bincode::{BorrowDecode, Encode, config::Configuration};
use bitflags::bitflags;
pub use native_path::NativePath;
pub use native_str::NativeStr;
use wincode::{SchemaRead, SchemaWrite};

pub const BINCODE_CONFIG: Configuration = bincode::config::standard();

#[derive(Encode, BorrowDecode, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
#[derive(SchemaWrite, SchemaRead, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
pub struct AccessMode(u8);

bitflags! {
Expand All @@ -35,7 +33,7 @@ impl Debug for AccessMode {
}
}

#[derive(Encode, BorrowDecode, Debug, Clone, Copy, PartialEq, Eq)]
#[derive(SchemaWrite, SchemaRead, Debug, Clone, Copy, PartialEq, Eq)]
pub struct PathAccess<'a> {
pub mode: AccessMode,
pub path: &'a NativePath,
Expand Down
Loading
Loading