Skip to content

Commit f1d78fc

Browse files
Auto merge of #143397 - folkertdev:test-variadic-call-from-rust-to-c, r=<try>
test passing a `VaList` from rust to C Have C define various functions that take a `...` or `va_list` as an argument, and call them from rust. As far as I can see, this just wasn't actually tested before. In particular this tests a difference between rust `VaList` and C `va_list` where C uses array-to-pointer decay, but rust cannot. I've locally tested this for - `x86_64-unknown-linux-gnu` - `aarch64-unknown-linux-gnu` - `s390x-unknown-linux-gnu` - `powerpc64-unknown-linux-gnu` - `powerpc64le-unknown-linux-gnu` The latter 2 use an opaque pointer, the first 3 use a single-element array. cc `@beetrees` if you see anything incorrect here r? `@workingjubilee` try-job: x86_64-msvc-* try-job: x86_64-apple-* try-job: aarch64-apple
2 parents 556d20a + a3277a1 commit f1d78fc

File tree

2 files changed

+104
-11
lines changed

2 files changed

+104
-11
lines changed

tests/run-make/c-link-to-rust-va-list-fn/checkrust.rs

Lines changed: 51 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
#![crate_type = "staticlib"]
22
#![feature(c_variadic)]
3+
#![feature(cfg_select)]
34

4-
use std::ffi::{CStr, CString, VaList, c_char, c_double, c_int, c_long, c_longlong};
5+
use std::ffi::{CStr, CString, VaList, VaListImpl, c_char, c_double, c_int, c_long, c_longlong};
56

67
macro_rules! continue_if {
78
($cond:expr) => {
@@ -19,15 +20,15 @@ unsafe fn compare_c_str(ptr: *const c_char, val: &str) -> bool {
1920
}
2021
}
2122

22-
#[no_mangle]
23+
#[unsafe(no_mangle)]
2324
pub unsafe extern "C" fn check_list_0(mut ap: VaList) -> usize {
2425
continue_if!(ap.arg::<c_longlong>() == 1);
2526
continue_if!(ap.arg::<c_int>() == 2);
2627
continue_if!(ap.arg::<c_longlong>() == 3);
2728
0
2829
}
2930

30-
#[no_mangle]
31+
#[unsafe(no_mangle)]
3132
pub unsafe extern "C" fn check_list_1(mut ap: VaList) -> usize {
3233
continue_if!(ap.arg::<c_int>() == -1);
3334
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 {
3940
0
4041
}
4142

42-
#[no_mangle]
43+
#[unsafe(no_mangle)]
4344
pub unsafe extern "C" fn check_list_2(mut ap: VaList) -> usize {
4445
continue_if!(ap.arg::<c_double>().floor() == 3.14f64.floor());
4546
continue_if!(ap.arg::<c_long>() == 12);
@@ -51,7 +52,7 @@ pub unsafe extern "C" fn check_list_2(mut ap: VaList) -> usize {
5152
0
5253
}
5354

54-
#[no_mangle]
55+
#[unsafe(no_mangle)]
5556
pub unsafe extern "C" fn check_list_copy_0(mut ap: VaList) -> usize {
5657
continue_if!(ap.arg::<c_double>().floor() == 6.28f64.floor());
5758
continue_if!(ap.arg::<c_int>() == 16);
@@ -64,14 +65,14 @@ pub unsafe extern "C" fn check_list_copy_0(mut ap: VaList) -> usize {
6465
)
6566
}
6667

67-
#[no_mangle]
68+
#[unsafe(no_mangle)]
6869
pub unsafe extern "C" fn check_varargs_0(_: c_int, mut ap: ...) -> usize {
6970
continue_if!(ap.arg::<c_int>() == 42);
7071
continue_if!(compare_c_str(ap.arg::<*const c_char>(), "Hello, World!"));
7172
0
7273
}
7374

74-
#[no_mangle]
75+
#[unsafe(no_mangle)]
7576
pub unsafe extern "C" fn check_varargs_1(_: c_int, mut ap: ...) -> usize {
7677
continue_if!(ap.arg::<c_double>().floor() == 3.14f64.floor());
7778
continue_if!(ap.arg::<c_long>() == 12);
@@ -80,12 +81,12 @@ pub unsafe extern "C" fn check_varargs_1(_: c_int, mut ap: ...) -> usize {
8081
0
8182
}
8283

83-
#[no_mangle]
84+
#[unsafe(no_mangle)]
8485
pub unsafe extern "C" fn check_varargs_2(_: c_int, _ap: ...) -> usize {
8586
0
8687
}
8788

88-
#[no_mangle]
89+
#[unsafe(no_mangle)]
8990
pub unsafe extern "C" fn check_varargs_3(_: c_int, mut ap: ...) -> usize {
9091
continue_if!(ap.arg::<c_int>() == 1);
9192
continue_if!(ap.arg::<c_int>() == 2);
@@ -100,7 +101,7 @@ pub unsafe extern "C" fn check_varargs_3(_: c_int, mut ap: ...) -> usize {
100101
0
101102
}
102103

103-
#[no_mangle]
104+
#[unsafe(no_mangle)]
104105
pub unsafe extern "C" fn check_varargs_4(_: c_double, mut ap: ...) -> usize {
105106
continue_if!(ap.arg::<c_double>() == 1.0);
106107
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 {
118119
0
119120
}
120121

121-
#[no_mangle]
122+
#[unsafe(no_mangle)]
122123
pub unsafe extern "C" fn check_varargs_5(_: c_int, mut ap: ...) -> usize {
123124
continue_if!(ap.arg::<c_double>() == 1.0);
124125
continue_if!(ap.arg::<c_int>() == 1);
@@ -148,3 +149,42 @@ pub unsafe extern "C" fn check_varargs_5(_: c_int, mut ap: ...) -> usize {
148149
continue_if!(ap.arg::<c_double>() == 13.0);
149150
0
150151
}
152+
153+
unsafe extern "C" {
154+
fn test_variadic(_: c_int, ...) -> usize;
155+
fn test_va_list_by_value(_: VaList) -> usize;
156+
fn test_va_list_by_pointer(_: *mut VaListImpl) -> usize;
157+
fn test_va_list_by_pointer_pointer(_: *mut *mut VaListImpl) -> usize;
158+
}
159+
160+
#[unsafe(no_mangle)]
161+
extern "C" fn run_test_variadic() -> usize {
162+
return unsafe { test_variadic(0, 1 as c_longlong, 2 as c_int, 3 as c_longlong) };
163+
}
164+
165+
#[unsafe(no_mangle)]
166+
extern "C" fn run_test_va_list_by_value() -> usize {
167+
unsafe extern "C" fn helper(mut ap: ...) -> usize {
168+
unsafe { test_va_list_by_value(ap.as_va_list()) }
169+
}
170+
171+
unsafe { helper(1 as c_longlong, 2 as c_int, 3 as c_longlong) }
172+
}
173+
174+
#[unsafe(no_mangle)]
175+
extern "C" fn run_test_va_list_by_pointer() -> usize {
176+
unsafe extern "C" fn helper(mut ap: ...) -> usize {
177+
unsafe { test_va_list_by_pointer(&mut ap) }
178+
}
179+
180+
unsafe { helper(1 as c_longlong, 2 as c_int, 3 as c_longlong) }
181+
}
182+
183+
#[unsafe(no_mangle)]
184+
extern "C" fn run_test_va_list_by_pointer_pointer() -> usize {
185+
unsafe extern "C" fn helper(mut ap: ...) -> usize {
186+
unsafe { test_va_list_by_pointer_pointer(&mut (&mut ap as *mut _)) }
187+
}
188+
189+
unsafe { helper(1 as c_longlong, 2 as c_int, 3 as c_longlong) }
190+
}

tests/run-make/c-link-to-rust-va-list-fn/test.c

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,11 @@ extern size_t check_varargs_3(int fixed, ...);
1515
extern size_t check_varargs_4(double fixed, ...);
1616
extern size_t check_varargs_5(int fixed, ...);
1717

18+
extern size_t run_test_variadic();
19+
extern size_t run_test_va_list_by_value();
20+
extern size_t run_test_va_list_by_pointer();
21+
extern size_t run_test_va_list_by_pointer_pointer();
22+
1823
int test_rust(size_t (*fn)(va_list), ...) {
1924
size_t ret = 0;
2025
va_list ap;
@@ -47,5 +52,53 @@ int main(int argc, char* argv[]) {
4752
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,
4853
9, 9.0, 10, 10.0, 11, 11.0, 12, 12.0, 13, 13.0) == 0);
4954

55+
assert(run_test_variadic() == 0);
56+
assert(run_test_va_list_by_value() == 0);
57+
assert(run_test_va_list_by_pointer() == 0);
58+
assert(run_test_va_list_by_pointer_pointer() == 0);
59+
60+
return 0;
61+
}
62+
63+
#define continue_if_else_end(cond) \
64+
do { if (!(cond)) { va_end(ap); return 0xff; } } while (0)
65+
66+
size_t test_variadic(int unused, ...) {
67+
va_list ap;
68+
va_start(ap, unused);
69+
70+
continue_if_else_end(va_arg(ap, long long) == 1);
71+
continue_if_else_end(va_arg(ap, int) == 2);
72+
continue_if_else_end(va_arg(ap, long long) == 3);
73+
74+
va_end(ap);
75+
76+
return 0;
77+
}
78+
79+
#define continue_if(cond) \
80+
do { if (!(cond)) { return 0xff; } } while (0)
81+
82+
size_t test_va_list_by_value(va_list ap) {
83+
continue_if(va_arg(ap, long long) == 1);
84+
continue_if(va_arg(ap, int) == 2);
85+
continue_if(va_arg(ap, long long) == 3);
86+
87+
return 0;
88+
}
89+
90+
size_t test_va_list_by_pointer(va_list *ap) {
91+
continue_if(va_arg(*ap, long long) == 1);
92+
continue_if(va_arg(*ap, int) == 2);
93+
continue_if(va_arg(*ap, long long) == 3);
94+
95+
return 0;
96+
}
97+
98+
size_t test_va_list_by_pointer_pointer(va_list **ap) {
99+
continue_if(va_arg(**ap, long long) == 1);
100+
continue_if(va_arg(**ap, int) == 2);
101+
continue_if(va_arg(**ap, long long) == 3);
102+
50103
return 0;
51104
}

0 commit comments

Comments
 (0)