1

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?

1
  • Yes, this answers my question! Commented Feb 15, 2022 at 8:23

1 Answer 1

5

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);
Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.