test rust calling a C C-variadic function

This commit is contained in:
Folkert de Vries
2025-07-03 20:39:32 +02:00
parent 6268d0aa34
commit a3277a1bbb
2 changed files with 104 additions and 11 deletions

View File

@@ -1,7 +1,8 @@
#![crate_type = "staticlib"]
#![feature(c_variadic)]
#![feature(cfg_select)]
use std::ffi::{CStr, CString, VaList, c_char, c_double, c_int, c_long, c_longlong};
use std::ffi::{CStr, CString, VaList, VaListImpl, c_char, c_double, c_int, c_long, c_longlong};
macro_rules! continue_if {
($cond:expr) => {
@@ -19,7 +20,7 @@ unsafe fn compare_c_str(ptr: *const c_char, val: &str) -> bool {
}
}
#[no_mangle]
#[unsafe(no_mangle)]
pub unsafe extern "C" fn check_list_0(mut ap: VaList) -> usize {
continue_if!(ap.arg::<c_longlong>() == 1);
continue_if!(ap.arg::<c_int>() == 2);
@@ -27,7 +28,7 @@ pub unsafe extern "C" fn check_list_0(mut ap: VaList) -> usize {
0
}
#[no_mangle]
#[unsafe(no_mangle)]
pub unsafe extern "C" fn check_list_1(mut ap: VaList) -> usize {
continue_if!(ap.arg::<c_int>() == -1);
continue_if!(ap.arg::<c_int>() == 'A' as c_int);
@@ -39,7 +40,7 @@ pub unsafe extern "C" fn check_list_1(mut ap: VaList) -> usize {
0
}
#[no_mangle]
#[unsafe(no_mangle)]
pub unsafe extern "C" fn check_list_2(mut ap: VaList) -> usize {
continue_if!(ap.arg::<c_double>().floor() == 3.14f64.floor());
continue_if!(ap.arg::<c_long>() == 12);
@@ -51,7 +52,7 @@ pub unsafe extern "C" fn check_list_2(mut ap: VaList) -> usize {
0
}
#[no_mangle]
#[unsafe(no_mangle)]
pub unsafe extern "C" fn check_list_copy_0(mut ap: VaList) -> usize {
continue_if!(ap.arg::<c_double>().floor() == 6.28f64.floor());
continue_if!(ap.arg::<c_int>() == 16);
@@ -64,14 +65,14 @@ pub unsafe extern "C" fn check_list_copy_0(mut ap: VaList) -> usize {
)
}
#[no_mangle]
#[unsafe(no_mangle)]
pub unsafe extern "C" fn check_varargs_0(_: c_int, mut ap: ...) -> usize {
continue_if!(ap.arg::<c_int>() == 42);
continue_if!(compare_c_str(ap.arg::<*const c_char>(), "Hello, World!"));
0
}
#[no_mangle]
#[unsafe(no_mangle)]
pub unsafe extern "C" fn check_varargs_1(_: c_int, mut ap: ...) -> usize {
continue_if!(ap.arg::<c_double>().floor() == 3.14f64.floor());
continue_if!(ap.arg::<c_long>() == 12);
@@ -80,12 +81,12 @@ pub unsafe extern "C" fn check_varargs_1(_: c_int, mut ap: ...) -> usize {
0
}
#[no_mangle]
#[unsafe(no_mangle)]
pub unsafe extern "C" fn check_varargs_2(_: c_int, _ap: ...) -> usize {
0
}
#[no_mangle]
#[unsafe(no_mangle)]
pub unsafe extern "C" fn check_varargs_3(_: c_int, mut ap: ...) -> usize {
continue_if!(ap.arg::<c_int>() == 1);
continue_if!(ap.arg::<c_int>() == 2);
@@ -100,7 +101,7 @@ pub unsafe extern "C" fn check_varargs_3(_: c_int, mut ap: ...) -> usize {
0
}
#[no_mangle]
#[unsafe(no_mangle)]
pub unsafe extern "C" fn check_varargs_4(_: c_double, mut ap: ...) -> usize {
continue_if!(ap.arg::<c_double>() == 1.0);
continue_if!(ap.arg::<c_double>() == 2.0);
@@ -118,7 +119,7 @@ pub unsafe extern "C" fn check_varargs_4(_: c_double, mut ap: ...) -> usize {
0
}
#[no_mangle]
#[unsafe(no_mangle)]
pub unsafe extern "C" fn check_varargs_5(_: c_int, mut ap: ...) -> usize {
continue_if!(ap.arg::<c_double>() == 1.0);
continue_if!(ap.arg::<c_int>() == 1);
@@ -148,3 +149,42 @@ pub unsafe extern "C" fn check_varargs_5(_: c_int, mut ap: ...) -> usize {
continue_if!(ap.arg::<c_double>() == 13.0);
0
}
unsafe extern "C" {
fn test_variadic(_: c_int, ...) -> usize;
fn test_va_list_by_value(_: VaList) -> usize;
fn test_va_list_by_pointer(_: *mut VaListImpl) -> usize;
fn test_va_list_by_pointer_pointer(_: *mut *mut VaListImpl) -> usize;
}
#[unsafe(no_mangle)]
extern "C" fn run_test_variadic() -> usize {
return unsafe { test_variadic(0, 1 as c_longlong, 2 as c_int, 3 as c_longlong) };
}
#[unsafe(no_mangle)]
extern "C" fn run_test_va_list_by_value() -> usize {
unsafe extern "C" fn helper(mut ap: ...) -> usize {
unsafe { test_va_list_by_value(ap.as_va_list()) }
}
unsafe { helper(1 as c_longlong, 2 as c_int, 3 as c_longlong) }
}
#[unsafe(no_mangle)]
extern "C" fn run_test_va_list_by_pointer() -> usize {
unsafe extern "C" fn helper(mut ap: ...) -> usize {
unsafe { test_va_list_by_pointer(&mut ap) }
}
unsafe { helper(1 as c_longlong, 2 as c_int, 3 as c_longlong) }
}
#[unsafe(no_mangle)]
extern "C" fn run_test_va_list_by_pointer_pointer() -> usize {
unsafe extern "C" fn helper(mut ap: ...) -> usize {
unsafe { test_va_list_by_pointer_pointer(&mut (&mut ap as *mut _)) }
}
unsafe { helper(1 as c_longlong, 2 as c_int, 3 as c_longlong) }
}

View File

@@ -15,6 +15,11 @@ extern size_t check_varargs_3(int fixed, ...);
extern size_t check_varargs_4(double fixed, ...);
extern size_t check_varargs_5(int fixed, ...);
extern size_t run_test_variadic();
extern size_t run_test_va_list_by_value();
extern size_t run_test_va_list_by_pointer();
extern size_t run_test_va_list_by_pointer_pointer();
int test_rust(size_t (*fn)(va_list), ...) {
size_t ret = 0;
va_list ap;
@@ -47,5 +52,53 @@ int main(int argc, char* argv[]) {
assert(check_varargs_5(0, 1.0, 1, 2.0, 2, 3.0, 3, 4.0, 4, 5, 5.0, 6, 6.0, 7, 7.0, 8, 8.0,
9, 9.0, 10, 10.0, 11, 11.0, 12, 12.0, 13, 13.0) == 0);
assert(run_test_variadic() == 0);
assert(run_test_va_list_by_value() == 0);
assert(run_test_va_list_by_pointer() == 0);
assert(run_test_va_list_by_pointer_pointer() == 0);
return 0;
}
#define continue_if_else_end(cond) \
do { if (!(cond)) { va_end(ap); return 0xff; } } while (0)
size_t test_variadic(int unused, ...) {
va_list ap;
va_start(ap, unused);
continue_if_else_end(va_arg(ap, long long) == 1);
continue_if_else_end(va_arg(ap, int) == 2);
continue_if_else_end(va_arg(ap, long long) == 3);
va_end(ap);
return 0;
}
#define continue_if(cond) \
do { if (!(cond)) { return 0xff; } } while (0)
size_t test_va_list_by_value(va_list ap) {
continue_if(va_arg(ap, long long) == 1);
continue_if(va_arg(ap, int) == 2);
continue_if(va_arg(ap, long long) == 3);
return 0;
}
size_t test_va_list_by_pointer(va_list *ap) {
continue_if(va_arg(*ap, long long) == 1);
continue_if(va_arg(*ap, int) == 2);
continue_if(va_arg(*ap, long long) == 3);
return 0;
}
size_t test_va_list_by_pointer_pointer(va_list **ap) {
continue_if(va_arg(**ap, long long) == 1);
continue_if(va_arg(**ap, int) == 2);
continue_if(va_arg(**ap, long long) == 3);
return 0;
}