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?
CodePudding user response:
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);