Skip to content

Commit 1d72037

Browse files
committed
Fix segfaults in release build C-variadic fns
`va_start` and `va_end` must be called to initialize/cleanup the "spoofed" `VaList` in a Rust defined C-variadic function even if the `VaList` is not used.
1 parent f22dca0 commit 1d72037

File tree

3 files changed

+27
-9
lines changed

3 files changed

+27
-9
lines changed

src/librustc_codegen_ssa/mir/block.rs

+7-2
Original file line numberDiff line numberDiff line change
@@ -233,8 +233,13 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
233233
mut bx: Bx,
234234
) {
235235
if self.fn_ty.c_variadic {
236-
if let Some(va_list) = self.va_list_ref {
237-
bx.va_end(va_list.llval);
236+
match self.va_list_ref {
237+
Some(va_list) => {
238+
bx.va_end(va_list.llval);
239+
}
240+
None => {
241+
bug!("C-variadic function must have a `va_list_ref`");
242+
}
238243
}
239244
}
240245
let llval = match self.fn_ty.ret.mode {

src/librustc_codegen_ssa/mir/mod.rs

+1-7
Original file line numberDiff line numberDiff line change
@@ -532,13 +532,7 @@ fn arg_local_refs<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>(
532532
PassMode::Ignore(IgnoreMode::Zst) => {
533533
return local(OperandRef::new_zst(bx.cx(), arg.layout));
534534
}
535-
PassMode::Ignore(IgnoreMode::CVarArgs) => {
536-
let backend_type = bx.cx().immediate_backend_type(arg.layout);
537-
return local(OperandRef {
538-
val: OperandValue::Immediate(bx.cx().const_undef(backend_type)),
539-
layout: arg.layout,
540-
});
541-
}
535+
PassMode::Ignore(IgnoreMode::CVarArgs) => {}
542536
PassMode::Direct(_) => {
543537
let llarg = bx.get_param(bx.llfn(), llarg_idx as c_uint);
544538
bx.set_value_name(llarg, &name);

src/test/codegen/c-variadic-opt.rs

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// compile-flags: -C opt-level=3
2+
3+
#![crate_type = "lib"]
4+
#![feature(c_variadic)]
5+
#![no_std]
6+
use core::ffi::VaList;
7+
8+
extern "C" {
9+
fn vprintf(fmt: *const i8, ap: VaList) -> i32;
10+
}
11+
12+
// Ensure that `va_start` and `va_end` are properly injected even
13+
// when the "spoofed" `VaList` is not used.
14+
#[no_mangle]
15+
pub unsafe extern "C" fn c_variadic_no_use(fmt: *const i8, mut ap: ...) -> i32 {
16+
// CHECK: call void @llvm.va_start
17+
vprintf(fmt, ap)
18+
// CHECK: call void @llvm.va_end
19+
}

0 commit comments

Comments
 (0)