So who is deallocating the returned string in confirm_hello_from_rust_compiled? Looks like you lost a fair bit of the safety checking in the Rust to C transition, if you didn't even have to mark the whole function unsafe.
In this small example we lost a lot of the safety, but for a larger library I'm hoping you could still keep most of the safety of Rust and just expose a smaller subsection of "unsafe" code.
Rust is freeing the string when the function ends, since to_ptr doesn't extended its lifetime.
C seems to be getting freed memory.
AFAIK the right way is to use mem::forget to "leak" memory when giving it to C, and later have C free it by calling a Rust function that casts it back to the original type.