Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I free a *char allocated via FFI in Rust?

Tags:

rust

ffi

I'm calling the LLVM API via Rust's FFI. LLVMPrintModuleToString uses strdup to create a string. However, when I wrap the pointer in a CString, I get an error when Rust drops it.

#![feature(cstr_memory)]
use std::ffi::CString;

extern crate llvm_sys as llvm;

fn main() {
    let llvm_ir_cstring;
    unsafe {
        let module = llvm::core::LLVMModuleCreateWithName(b"nop\0".as_ptr() as *const _);
        let llvm_ir_char_ptr = llvm::core::LLVMPrintModuleToString(module);
        llvm::core::LLVMDisposeModule(module);
        llvm_ir_cstring = CString::from_ptr(llvm_ir_char_ptr);
    }

    println!("llvm_ir_cstring: {:?}", llvm_ir_cstring);
}

Valgrind error:

==10413== Invalid read of size 4
==10413==    at 0x4870586: pthread_mutex_lock (in /usr/lib/libpthread-2.21.so)
==10413==    by 0x17F89B: je_arena_dalloc_small (in /home/wilfred/projects/bfc/target/debug/bfc)
==10413==    by 0x178C30: je_sdallocx (in /home/wilfred/projects/bfc/target/debug/bfc)
==10413==    by 0x10FA57: heap::imp::deallocate::h1fb92d59333c497bkja (heap.rs:268)
==10413==    by 0x10F999: heap::deallocate::h5680e3fedc9e96320da (heap.rs:89)
==10413==    by 0x10F929: heap::exchange_free::h452463f962f7ec23kfa (heap.rs:131)
==10413==    by 0x10F8C5: Box$LT$$u5b$u8$u5d$$GT$::drop.1769::haf7017472635c7cf (in /home/wilfred/projects/bfc/target/debug/bfc)
==10413==    by 0x10F836: std..ffi..c_str..CString::drop.1766::h04d2b3db8d468f0c (in /home/wilfred/projects/bfc/target/debug/bfc)
==10413==    by 0x10F5FF: main::h04b7feb343e229ccgaa (in /home/wilfred/projects/bfc/target/debug/bfc)
==10413==    by 0x16DBCA: rt::unwind::try::try_fn::h2403085009213705177 (in /home/wilfred/projects/bfc/target/debug/bfc)
==10413==    by 0x16FF5A: rust_try_inner (in /home/wilfred/projects/bfc/target/debug/bfc)
==10413==    by 0x16FF33: rust_try (in /home/wilfred/projects/bfc/target/debug/bfc)
==10413==  Address 0x1d684 is not stack'd, malloc'd or (recently) free'd

Why is this? What's the correct way to handle a *char from a C API?

like image 387
Wilfred Hughes Avatar asked Jul 18 '15 00:07

Wilfred Hughes


1 Answers

According to the function's documentation:

Use LLVMDisposeMessage to free the string.

In the general case, if you call a function in a library that allocates memory, you should call another function in that library that frees the memory; this should generally be documented as part of the function's contract.

If the documentation for a function tells you to use free, then you'll have a problem if your application is not linking with the free corresponding to the library's malloc (e.g. your application links with msvcr120, but the library links with msvcr100). This is the reason why good libraries provide a method to deallocate resources that it allocates for you.

The default memory allocator in Rust is not C's malloc, but another allocator called jemalloc. CString assumes the string was allocated with Rust's memory allocator, so when CString's destructor runs, it runs jemalloc's free (you can tell from the je_-prefixed functions in your call stack), but it fails because the string wasn't allocated with jemalloc's malloc.

like image 77
Francis Gagné Avatar answered Sep 20 '22 15:09

Francis Gagné