3

I'm trying to call some Rust code from C and get a result back, but I'm getting a "pointer being freed was not allocated" error on the Rust side.

I want to call the hex::encode function. I pass in a pointer to some bytes, the length, and a pointer allocated in C with malloc. I want the result of the conversion passed back at this pointer.

The Rust function:

extern crate libc; use hex; use std::ffi::CString; use std::os::raw::c_char; use std::vec::Vec; use std::{ffi, ptr, slice}; #[no_mangle] pub extern "C" fn bytes_to_hex_string(bp: *mut u8, bp_size: usize, sp: *mut c_char) -> i8 { println!("1"); let p_vec = unsafe { Vec::from_raw_parts(bp, bp_size, bp_size + 1) }; println!("2"); let str = hex::encode(p_vec); println!("3"); let bytes = str.as_bytes(); println!("4"); let cs = CString::new(bytes).unwrap(); // will fail if bytes has "gap" (null) in sequence println!("5"); unsafe { libc::strcpy(sp, cs.as_ptr()); } println!("6"); return 1; } 

Called from this C code:

#include <string.h> #include <stdio.h> #include <stdlib.h> int8_t bytes_to_hex( uint8_t *, unsigned int, char *); int main() { char *ptr = "Hello World!"; char *hex = (char *)malloc(1000); printf("about to call....\n"); bytes_to_hex_string((uint8_t*)ptr,strlen(ptr),hex); printf("about to print....\n"); printf("%s\n",hex); printf("about to free....\n"); free(hex); } 

When I run the program:

$ ./a.out about to call.... 1 2 a.out(2941,0x7fffccae03c0) malloc: *** error for object 0x10afe2b80: pointer being freed was not allocated *** set a breakpoint in malloc_error_break to debug Abort trap: 6 

It looks like the Rust code inside the hex crate is freeing the ptr pointer, is that right?

Is there a way round this somehow? I would prefer for the allocation and freeing to happen in C, but I am open to any suggestions to solve this!

1
  • From the documentation on Vec::from_raw_parts: "ptr needs to have been previously allocated via String/Vec<T> (at least, it's highly likely to be incorrect if it wasn't)." Generally, it is meant to be used as a way to recover a Vec that was previously disassembled/forgotten, not as a way to create vectors from an arbitrary memory buffer. As the answer suggests, turning these raw parts into a slice is most likely the right way to go. Commented Oct 4, 2018 at 16:27

1 Answer 1

4

If you don't want Rust to deallocate your pointer, don't use types that own the allocation. Vec and CString both take ownership of the pointer and manage it. Presumably you were surprised to need to provide both a length and a capacity?

Use slice::from_raw_parts instead:

extern crate libc; extern crate hex; use std::ffi::CString; use std::os::raw::c_char; use std::slice; #[no_mangle] pub unsafe extern "C" fn bytes_to_hex_string(bp: *mut u8, bp_size: usize, sp: *mut c_char) -> i8 { let p_vec = slice::from_raw_parts(bp, bp_size); let str = hex::encode(p_vec); let cs = CString::new(str).unwrap(); libc::strcpy(sp, cs.as_ptr()); return 1; } 

I didn't test this, so I cannot say if your strcpy is correct. Panicking in a FFI function is undefined behavior, however. It's also surprising that you declare both pointers as mutable... You also don't need to import Vec as it's in the prelude.

See also:

Sign up to request clarification or add additional context in comments.

1 Comment

It worked. And I made the first pointer const, like you said. I didn't know some types manage and others don't. A lot to learn for rust :( Many thanks.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.