[SOLVED] Why linking and calling a C function with variadic arguments in Rust causes random functions to be called?

Issue

I was playing with Rust FFI and I was trying to link printf C function, which has variadic arguments, with my Rust executable. After I ran the executable I witnessed some strange behavior.

This is my Rust code:

use cty::{c_char, c_int};

extern "C" {
    fn printf(format: *const c_char, ...) -> c_int;
}

fn main() {
    unsafe {
        printf("One number: %d\n".as_ptr() as *const i8, 69);
        printf("Two numbers: %d %d\n".as_ptr() as *const i8, 11, 12);
        printf(
            "Three numbers: %d %d %d\n".as_ptr() as *const i8,
            30,
            31,
            32,
        );
    }
}

This is the output after running cargo run:

cargo run
   Compiling c-bindings v0.1.0 (/home/costin/Rust/c-bindings)
    Finished dev [unoptimized + debuginfo] target(s) in 0.20s
     Running `target/debug/c-bindings`
One number: 1
Two numbers: 1 11376
Three numbers: 0 0 0
Two numbers: 11 12
Three numbers: 0 0 56
Three numbers: 30 31 32

I looks like the first printf calls the second and the third with random parameters, then the second printf calls the third one with random parameters because the expected output should have been:

One number: 1
Two numbers: 11 12
Three numbers: 30 31 32

Can anyone explain to me why is this strange behavior happening?

Solution

Rust strings are not null-terminated like printf expects. You’ll need to either manually include \0 at the end of your format strings or use CString:

printf("One number: %d\n\0".as_ptr() as *const i8, 69);
use std::ffi::CString;
let s = CString::new("One number: %d\n").unwrap();
printf(s.as_ptr(), 69);

Answered By – kmdreko

Answer Checked By – Candace Johnson (BugsFixing Volunteer)

Leave a Reply

Your email address will not be published.