I try to wrap printf
just like the following code:
extern crate libc;
use libc::{c_char, c_int};
extern "C" {
fn printf(fmt: *const c_char, ...) -> c_int;
}
fn main() {
unsafe {
printf("hello world\n".as_ptr() as *const i8);
}
}
But it prints something really strange...
However, if I append extra
\0
to string I want to print, it prints properly.
extern crate libc;
use libc::{c_char, c_int};
extern "C" {
fn printf(fmt: *const c_char, ...) -> c_int;
}
fn main() {
unsafe {
printf("hello world\n\0".as_ptr() as *const i8);
}
}
Is it a bug or I didn't wrap the C function properly?
C strings are zero-terminated. Rust strings are not. This is why the CStr
and CString
types exist.
5 Likes
kornel
September 12, 2018, 2:30pm
4
Warning in advance - assing CString
to a variable before calling as_ptr()
on it. Temporary value (not assigned to a variable) will give invalid, crash-inducing pointer.
I always like linking to your original post on the CString::as_ptr()
issue.
I knew that CString::new().as_ptr() is dangerous, so I consciously avoided that convenient construct, and still, I got a use-after-free.
I needed a nullable string for a C function, so I wrote:
let option = Some("foo");
// Explicitly bind CString to a variable to keep it alive
let c_option = option.and_then(|s| CString::new(s).ok());
// And it's not alive! This causes use-after-free, and Rust is doesn't say a word about it
let p = c_option.map(|c| c.as_ptr()).unwrap_or(ptr::null());
// And…