Skip to content

Commit

Permalink
Remove reliance on sptr and exposing provenance
Browse files Browse the repository at this point in the history
  • Loading branch information
MolotovCherry committed Dec 18, 2024
1 parent d6c2682 commit 68d978b
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 33 deletions.
23 changes: 8 additions & 15 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 0 additions & 2 deletions crates/yabg3nml/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,6 @@ tracing-appender = "0.2.3"
pelite = "0.10.0"
widestring = "1.1.0"
rand = "0.8.5"
# todo: remove sptr when strict provenance apis are stable
sptr = "0.3.2"

[dependencies.argh]
git = "https://github.com/google/argh"
Expand Down
68 changes: 53 additions & 15 deletions crates/yabg3nml/src/wapi/enum_windows.rs
Original file line number Diff line number Diff line change
@@ -1,46 +1,84 @@
use std::panic::{self, AssertUnwindSafe};
use std::{
mem,
panic::{self, AssertUnwindSafe},
sync::Mutex,
};

use eyre::Result;
// TODO: remove when strict provenance apis are stable
use sptr::{from_exposed_addr_mut, Strict};
use shared::utils::SuperLock;
use tracing::{error, trace_span};
use windows::Win32::{
Foundation::{BOOL, FALSE, HWND, LPARAM, TRUE},
Foundation::{BOOL, HWND, LPARAM},
UI::WindowsAndMessaging::EnumWindows,
};

type UserCallback<'a> = Box<dyn FnMut(HWND) -> Result<()> + Send + Sync + 'a>;

struct FfiCb(UserCallback<'static>);

trait StaticFfiCbMethods {
unsafe fn set_cb(&self, cb: UserCallback);
unsafe fn call(&self, hwnd: HWND) -> Result<()>;
fn drop(&self);
}

impl StaticFfiCbMethods for Mutex<Option<FfiCb>> {
/// SAFETY:
/// Caller promises to drop before end of scope where original closure was created
/// this is because closure may have captures, this is !'static
unsafe fn set_cb(&self, cb: UserCallback) {
let _static = unsafe { mem::transmute::<UserCallback, UserCallback<'static>>(cb) };
*self.super_lock() = Some(FfiCb(_static));
}

/// SAFETY:
/// This must be called in scope where closure captures are still valid
unsafe fn call(&self, hwnd: HWND) -> Result<()> {
if let Some(cb) = &mut *self.super_lock() {
cb.0(hwnd)
} else {
Ok(())
}
}

fn drop(&self) {
*self.super_lock() = None;
}
}

static CB: Mutex<Option<FfiCb>> = Mutex::new(None);

#[allow(non_snake_case)]
pub fn EnumWindowsRs(cb: impl FnMut(HWND) -> Result<()> + Send + Sync) {
let span = trace_span!("EnumWindowsRs");
let _guard = span.enter();

let mut cb: UserCallback = Box::new(cb);
// TODO: Use strict provenance apis when stable and remove sptr
_ = unsafe { EnumWindows(Some(enum_cb), LPARAM((&raw mut cb).expose_addr() as _)) };
unsafe {
CB.set_cb(Box::new(cb));
}

_ = unsafe { EnumWindows(Some(enum_cb), None) };

CB.drop();
}

extern "system" fn enum_cb(param0: HWND, param1: LPARAM) -> BOOL {
extern "system" fn enum_cb(param0: HWND, _: LPARAM) -> BOOL {
let span = trace_span!("enum_cb");
let _guard = span.enter();

// TODO: Use strict provenance apis when stable and remove sptr
let cb = unsafe { &mut *from_exposed_addr_mut::<UserCallback>(param1.0 as _) };

let result = panic::catch_unwind(AssertUnwindSafe(|| cb(param0)));
let result = panic::catch_unwind(AssertUnwindSafe(|| unsafe { CB.call(param0) }));

match result {
// no panic and cb returned Ok
Ok(Ok(_)) => TRUE,
Ok(Ok(_)) => true.into(),

// no panic and callback returned Err
Ok(Err(err)) => {
error!("{err}");
FALSE
false.into()
}

// panic
Err(_) => FALSE,
Err(_) => false.into(),
}
}
2 changes: 1 addition & 1 deletion rust-toolchain.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
[toolchain]
channel = "nightly-2024-11-17"
channel = "nightly-2024-12-17"
components = ["rustfmt", "clippy"]
profile = "minimal"

0 comments on commit 68d978b

Please sign in to comment.