dll_syringe_payload_utils/
lib.rs1#![warn(unsafe_op_in_unsafe_fn)]
2#[macro_export]
35macro_rules! remote_procedure {
36 ($(pub)? fn $fn:ident ( $($name:ident : $type:ty),* )
37 $body:block
38 ) => {
39 $crate::remote_procedure! {
40 pub fn $fn ( $($name : $type),* ) -> () $body
41 }
42 };
43 ($(pub)? fn $fn:ident ( $($name:ident : $type:ty),* ) -> $ret:ty
44 $body:block
45 ) => {
46 #[no_mangle]
47 pub unsafe extern "system" fn $fn ( __args: *const ($($type ,)*), __result: *mut $ret ) {
48 fn __inner ( $($name : $type),* ) -> $ret $body
49
50 let ($($name ,)*) = unsafe { ::core::ptr::read(__args) };
51 unsafe { ::core::ptr::write(__result, __inner($($name ,)*)) };
52 }
53 };
54}
55
56#[cfg(test)]
57mod tests {
58 use std::{mem::MaybeUninit, ptr};
59
60 #[test]
61 fn does_not_drop_uninit_result() {
62 pub struct NoImplicitDrop(u32);
63
64 impl Drop for NoImplicitDrop {
65 fn drop(&mut self) {
66 assert_ne!(self.0, 0, "dropped before being initialized");
67 }
68 }
69
70 impl NoImplicitDrop {
71 fn new() -> Self {
72 Self(1)
73 }
74 }
75
76 remote_procedure! {
77 fn add() -> NoImplicitDrop {
78 NoImplicitDrop::new()
79 }
80 }
81
82 let mut result = MaybeUninit::uninit();
83 unsafe { add(&(), result.as_mut_ptr()) };
84 }
85
86 #[test]
87 fn works_with_byte_buf() {
88 remote_procedure! {
89 fn pass_bytes(_arg: &[u8]) {
90 }
91 }
92 }
93
94 #[test]
95 fn takes_ownership_of_arg() {
96 pub struct NoCopy(u32);
97
98 impl Drop for NoCopy {
99 fn drop(&mut self) {}
100 }
101
102 static mut STORAGE: Option<NoCopy> = None;
103
104 remote_procedure! {
105 fn takes_ownership(arg: NoCopy) {
106 unsafe { STORAGE = Some(arg) }
107 }
108 }
109
110 let mut arg = NoCopy(1);
111 let arg_ptr = &mut arg as *mut NoCopy;
112 unsafe { takes_ownership(arg_ptr.cast(), &mut ()) };
113 unsafe { ptr::write(arg_ptr, NoCopy(2)) };
114
115 assert_eq!(unsafe { STORAGE.take() }.unwrap().0, 1);
116 }
117}