I am working ona LD_PRELOAD program that aims to intercept open system call is variadic.
int open(const char *pathname, int flags, ...)
I am extending an open source library call redhook and extending to support variadic functions.
I have duplicated their existing hook and real macros to hookv and realv to handle the variadic case.
Rustc 1.45.0 which is expected to have support for variadic functions is in use.
I am seeing the following error when compiling the code.
error: no rules expected the token `...`
--> src/lib.rs:9:61
|
9 | unsafe fn open(path: *const c_char, flags: c_int, args: ...) -> c_int => my_open {
| ^^^ no rules expected this token in macro call
From the looks of the compiler error message, it looks like rust macro expansion cannot handle "..." as a type
The macro invocation is as follows
hookv! {
unsafe fn open(path: *const c_char, flags: c_int, args: ...) -> c_int => my_open {
if let Ok(path) = std::str::from_utf8(std::ffi::CStr::from_ptr(path).to_bytes()) {
println!("open(\"{}\")", path);
}
realv!(open)(path, flags, args)
}
}
It looks like the macro definition is not able to map "..." to match $t:ty
unsafe fn $real_fn:ident ( $($v:ident : $t:ty),* ) -> $r:ty
The macro definition of hookv is defined is as follows, to expand
#[macro_export]
macro_rules! hookv {
(unsafe fn $real_fn:ident ( $($v:ident : $t:ty),* ) -> $r:ty => $hook_fn:ident $body:block) => {
#[allow(non_camel_case_types)]
pub struct $real_fn {__private_field: ()}
#[allow(non_upper_case_globals)]
static $real_fn: $real_fn = $real_fn {__private_field: ()};
impl $real_fn {
fn get(&self) -> unsafe extern "C" fn ( $($v : $t),* ) -> $r {
use ::std::sync::Once;
static mut REAL: *const u8 = 0 as *const u8;
static mut ONCE: Once = Once::new();
unsafe {
ONCE.call_once(|| {
REAL = $crate::ld_preload::dlsym_next(concat!(stringify!($real_fn), "\0"));
});
::std::mem::transmute(REAL)
}
}
#![feature(c_variadic)]
#[no_mangle]
pub unsafe extern "C" fn $real_fn ( $($v : $t),*) -> $r {
if $crate::initialized() {
::std::panic::catch_unwind(|| $hook_fn ( $($v),* )).ok()
} else {
None
}.unwrap_or_else(|| $real_fn.get() ( $($v),* ))
}
}
pub unsafe fn $hook_fn ( $($v : $t),* ) -> $r {
$body
}
};
(unsafe fn $real_fn:ident ( $($v:ident : $t:ty),* ) => $hook_fn:ident $body:block) => {
$crate::hook! { unsafe fn $real_fn ( $($v : $t),* ) -> () => $hook_fn $body }
};
}
#[macro_export]
macro_rules! realv {
($real_fn:ident) => {
$real_fn.get()
};
}