Skip to content
tezvyn:

Use a C malloc'd char* in Go and Rust, then free it

Source: gist.github.comMediumHow cards are made

Use a C malloc'd char* in Go and Rust, then free it

Tests FFI allocator discipline. In Go, copy with C.GoString then C.free the *C.char. In Rust, read via CStr::from_ptr, copy to String, then libc::free. Red flag: letting Go GC or Rust Drop manage C memory, or using CString::from_raw on C malloc'd pointers.

What's really being asked

Cross-language FFI memory ownership and allocator discipline. The core issue is that C heap memory is invisible to Go's garbage collector and Rust's ownership system, so you must manually pair allocation and deallocation across the boundary. The interviewer is checking that you know copying is usually required for safe native use, and that freeing must use the original allocator or a library-provided free function.

A GOOD ANSWER COVERS four things in order. First, in Go via cgo: import C and include stdlib.h, call the function to get a C.char, immediately copy it into a Go-managed string with C.GoString, then release the C buffer with C.free(unsafe.Pointer(ptr)). Second, in Rust: call the function inside an unsafe extern block to obtain a mut c_char, read it with std::ffi::CStr::from_ptr and copy the contents into a Rust String or str, then free the original pointer. Because the memory came from C malloc, you free it with libc::free or, more robustly, with a dedicated free function exposed by the library itself. Third, explicitly note that CString::from_raw is for Rust-allocated strings only; using it on a C malloc'd pointer is undefined behavior because it may invoke the wrong allocator. Fourth, state the production rule: the library should expose its own free function rather than forcing consumers to call malloc or free directly, since the library might be compiled with a different allocator or actually be implemented in Rust.

COMMON WRONG ANSWERS include several red flags. Letting the pointer leak because Go will GC it or Rust will drop it; neither runtime manages C heap memory. In Rust, wrapping the pointer in CString and dropping it, which corrupts the heap if the global allocators differ. In Go, forgetting to free the *C.char after converting it with C.GoString. Also, calling free on the copied Go or Rust string instead of the original C pointer.

LIKELY FOLLOW-UPS the interviewer may ask next. What if the library is actually written in Rust? You still treat it as C FFI and insist on a library-provided free function, because Rust allocations must be freed by Rust. How do you make the Rust side panic-safe? Wrap the raw pointer in a struct that implements Drop to call the C free function, ensuring cleanup even during unwinding. What if the string can contain interior null bytes? CStr reads until the first null, so you would need a pointer-plus-length API instead.

ONE CONCRETE EXAMPLE. In Go: ptr := C.get_message(); s := C.GoString(ptr); C.free(unsafe.Pointer(ptr)); then use s. In Rust: let ptr = unsafe { get_message() }; let s = unsafe { CStr::from_ptr(ptr).to_string_lossy().into_owned() }; unsafe { libc::free(ptr as *mut libc::c_void); } then use s.

Interview question

In Rust, you receive a *mut c_char allocated by C malloc. Which sequence safely produces a Rust String without corrupting the heap?

  • a.Copy the data into a String with CStr::from_ptr and let the raw pointer leak
  • b.Use CString::from_raw to take ownership, convert to String, and let CString drop it
  • c.Call libc::free on the new Rust String after copying with CStr::from_ptr
  • d.Use CStr::from_ptr to read and copy the data, then free the original pointer with libc::freeCorrect
Why?

The card states you must copy the C string via CStr::from_ptr and then free the original pointer with libc::free. Option B is undefined behavior because CString::from_raw may use Rust's allocator on C malloc'd memory, and Option A leaks memory since Rust's ownership system does not manage C heap memory.

Just read this? Test yourself on what you have been reading.

Read the original → gist.github.com

You just looked this up. Could you explain it out loud?

That is the part interviews actually test. Tezvyn takes questions like this one and gives you what the interviewer is really checking, the answer that lands, and the mistake that ends the conversation, in the four minutes before your next meeting.

The iPhone app is on the way

We are building it. Until it lands, nothing here is held back from you: every interview card, your saved cards, streaks and the job board all work in Safari, plus hundreds of free practice quizzes of thirty questions each. Sign in and it all carries over to the app the day it arrives.

Want it as an icon? Tap Share at the bottom of Safari, then Add to Home Screen. It opens full screen and the cards you have read stay available offline.

Get it on Google PlayiPhone app coming soon

We are hiring for this. Every open role lists the topics its interview covers, so you can prepare for the real thing rather than guessing.

See open roles