Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Segfault when using C compatible variadic functions #58980

Closed
thedataking opened this issue Mar 7, 2019 · 2 comments · Fixed by #58985
Closed

Segfault when using C compatible variadic functions #58980

thedataking opened this issue Mar 7, 2019 · 2 comments · Fixed by #58985
Labels
A-FFI Area: Foreign function interface (FFI) C-bug Category: This is a bug. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@thedataking
Copy link

This example prints test 1 2 3 when compiled and run in debug mode:

#![feature(c_variadic)]

extern "C" {
    #[no_mangle]
    fn vprintf(_: *const libc::c_char, _: ...) -> libc::c_int;
}

#[no_mangle]
unsafe extern "C" fn variadic(fmt: *const libc::c_char, a: ...)
 -> libc::c_int {
    vprintf(fmt, a)
}

fn main() {
    let fmt = std::ffi::CString::new("test %d %d %d\n").expect("new failed");
    unsafe {
        variadic(fmt.as_ptr(), 1, 2, 3);
    }
}

Compiling and running in release mode causes a segfault in glibc/stdio-common/vfprintf.c:1286 because ap is nul. Enabling debug info in release mode via Cargo.toml makes the segfault go away.

Meta

$ rustc --version --verbose
rustc 1.35.0-nightly (f22dca0a1 2019-03-05)
binary: rustc
commit-hash: f22dca0a1bef4141e75326caacc3cd59f3d5be8e
commit-date: 2019-03-05
host: x86_64-unknown-linux-gnu
release: 1.35.0-nightly
LLVM version: 8.0
@dlrobertson
Copy link
Contributor

@thedataking thanks for reporting this. The example should probably look more like the following. The example still segfaults (even in debug mode).

#![feature(c_variadic)]
use std::ffi::VaList;

extern "C" {
    // vprintf signature is `int vprintf(const char * format, va_list arg)`
    #[no_mangle]
    fn vprintf(_: *const libc::c_char, _: VaList) -> libc::c_int;
}

#[no_mangle]
unsafe extern "C" fn variadic(fmt: *const libc::c_char, a: ...) -> libc::c_int {
    // `va_start` in theory should be automatically called giving you a
    // `VaList` at `a` here.
    vprintf(fmt, a)
    // `va_end` should be called here.
}

fn main() {
    let fmt = std::ffi::CString::new("test %d %d %d\n").expect("new failed");
    unsafe {
        variadic(fmt.as_ptr(), 1, 2, 3);
    }
}

If a is used in the function variadic the issue does not happen. Essentially we're optimizing variadic to the following

define i32 @variadic(i8* %fmt, ...) unnamed_addr #3 personality i32 (i32, i32, i64, %"unwind::libunwind::_Unwind_Exception"*, %"unwind::libunwind::_Unwind_Context"*)* @rust_eh_personality {
start:
  %personalityslot = alloca { i8*, i32 }, align 8
  %0 = invoke i32 @vprintf(i8* %fmt, i64* align 8 dereferenceable(24) undef)
          to label %bb2 unwind label %cleanup
  ...

Note the missing va_start and va_end. I think this is happening because we're hitting src/librustc_codegen_ssa/mir/mod.rs:536-540. I'll do some more investigation shortly.

@dlrobertson
Copy link
Contributor

dlrobertson commented Mar 7, 2019

@thedataking the code I list in the above example should work after #58985 is merged.

@jonas-schievink jonas-schievink added A-FFI Area: Foreign function interface (FFI) T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. C-bug Category: This is a bug. labels Mar 7, 2019
bors added a commit that referenced this issue Mar 8, 2019
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.

r? @alexreg
Fixes: #58980
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-FFI Area: Foreign function interface (FFI) C-bug Category: This is a bug. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants