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

?

+3


source to share


1 answer


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!");
    }
}

      

+3


source







All Articles