Recently I was playing around with the Kotlin native platform and the C Interoperability that offers.
I’m trying to wrap a rust library (that also makes use of the async-io, with the tokio runtime).
I have the following kotlin code:
override suspend fun rustFn(aString: String) {
a_rust_fn(aString, fn)
}
companion object {
private val fn = staticCFunction<ULong, Unit> { idx ->
println("Callback $idx")
}
}
I also have the rust code:
#[no_mangle]
pub extern "C" fn a_rust_fn(
a_string: *const c_char,
fun: unsafe extern "C" fn(idx: u64),
) {
let a_string = c_chars_to_str(a_string).unwrap();
let runtime = RUNTIME.get().unwrap(); // get the tokio runtime from a static memory space
runtime.spawn(async move {
println!("{}", a_string); // Here the string is corrupted
unsafe { fun(idx) }
});
}
fn c_chars_to_str<'a>(c_chars: *const c_char) -> ResultCode<&'a str> {
let c_str = unsafe { CStr::from_ptr(c_chars) };
let str = c_str.to_str().map_err(|_| INVALID_STRING_CONVERSION)?;
Ok(str)
}
The problem is that inside the async move
block the string is corrupted. It seems that the kotlin runtime has deallocated the memory at this point.
I wonder how I could “tell” to kotlin to keep in memory this String until I manually free it. Is there a way?