Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

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

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:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

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);
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading