Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Auto merge of #25777 - shepmaster:cstring-return-to-c, r=alexcrichton
As far as I was able to determine, it's currently *impossible* to allocate a C NUL-terminated string in Rust and then return it to C (transferring ownership), without leaking memory. There is support for passing the string to C (borrowing). To complicate matters, it's not possible for the C code to just call `free` on the allocated string, due to the different allocators in use. `CString` has no way to recreate itself from a pointer. This commit adds one. This is complicated a bit because Rust `Vec`s want the pointer, size, and capacity. To deal with that, another method to shrink and "leak" the `CString` to a `char *` is also provided. We can then use `strlen` to determine the length of the string, which must match the capacity. **TODO** - [x] Improve documentation - [x] Add stability markers - [x] Convert to `Box<[u8]>` ### Example code With this example code: ```rust #![feature(libc)] #![feature(cstr_to_str)] #![feature(c_str_memory)] extern crate libc; use std::ffi::{CStr,CString}; #[no_mangle] pub extern fn reverse(s: *const libc::c_char) -> *const libc::c_char { let s = unsafe { CStr::from_ptr(s) }; let s2 = s.to_str().unwrap(); let s3: String = s2.chars().rev().collect(); let s4 = CString::new(s3).unwrap(); s4.into_ptr() } #[no_mangle] pub extern fn cleanup(s: *const libc::c_char) { unsafe { CString::from_ptr(s) }; } ``` Compiled using `rustc --crate-type dylib str.rs`, I was able to link against it from C (`gcc -L. -l str str.c -o str`): ```c #include <stdio.h> extern char *reverse(char *); extern void cleanup(char *); int main() { char *s = reverse("Hello, world!"); printf("%s\n", s); cleanup(s); } ``` As well as dynamically link via Ruby: ```ruby require 'fiddle' require 'fiddle/import' module LibSum extend Fiddle::Importer dlload './libstr.dylib' extern 'char* reverse(char *)' extern 'void cleanup(char *)' end s = LibSum.reverse("hello, world!") puts s LibSum.cleanup(s) ```
- Loading branch information