FFI line C: Is there something like String :: from_raw_buf_with_max_len
Note (May 2015): This question was about the rust language before it stabilized and 1.0 was released and is now mostly of historical interest: the code won't compile on stable rust, etc.
I am writing a wrapper on top of libpcap for a project I am working on and learning Rust (which I just started doing). I am currently working on writing reliable rust:
#[link(name = "pcap")]
extern {
fn pcap_lookupdev(errormsg: *mut libc::c_char) -> *const libc::c_char;
}
Here's what I have so far:
fn lookupdev() -> Result<String, String> {
// Capacity must be at least PCAP_ERRBUF_SIZE
let mut errbuf = [0 as c_char, ..256];
let result = unsafe {
let ptr = pcap_lookupdev(errbuf.as_mut_ptr() as *mut libc::c_char);
if ptr.is_null() {
None
}
else {
Some(CString::new(ptr, false))
}
};
match result {
Some(result) => Ok(result.as_str().unwrap().to_string()),
None => Err(unsafe { String::from_raw_buf(errbuf.as_ptr() as *const u8) })
}
}
This works, but I don't like the use String::from_raw_buf
that will happily walk the whole gigabyte of memory, rather than stop when it reaches the end of the errbuf.
I can write something that loops on errbuf
manually and converts it to a Rust string (stops at the end of the buffer), but in my opinion this is the C FFI idiom for strings (pass an allocated block of memory where the string can be written) which must be supported by the Rust standard library. However, I couldn't find anything in the Rust RFI manual or in the standard library documentation.
What's the best way to handle this FFI case in Rust? Is there at least String::from_raw_buf_with_maxlen
or String::from_array
?
source to share
The Rust standard library itself doesn't really handle this possibility:
This is probably unintentional, and IMO, the bug must be filed with Rust.
So I don't think there is an easy solution right now. The one I can think of is this
#![feature(slicing_syntax)]
extern crate libc;
use std::c_str::CString;
fn main() {
let errbuf = ['o' as libc::c_char; 256];
if errbuf.iter().any(|c| *c == 0 as libc::c_char) {
unsafe { CString::new(errbuf.as_ptr(), false).to_string() };
} else {
panic!("FFI returned invalid string!");
}
}
source to share