C Variadic functions in rust macro showing error

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()
    };
}

Just an fyi: This forum does have support for displaying code properly, though it isn't obvious. Here's how to use it.

Yes, that's macro failing to support variadic args. ... is not a type. It's an interesting problem — macros don't seem to have a specific type that matches ...: https://doc.rust-lang.org/reference/macros-by-example.html#metavariables

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.