¿Cómo puedo llenar un vector Rust no inicializado usando una función en C?
Estoy tratando de llamar a una función de C que rellena un vector desde Rust. Aquí hay un ejemplo mínimo completo:
Cargo.toml
[package]
name = "so"
version = "0.1.0"
edition = "2021"
[build-dependencies]
cc = "1.0.72"
build.rs
fn main() {
cc::Build::new().file("src/library.c").compile("library");
}
src/library.c
void get_ui_array(unsigned long *out, long len) {
long i;
for (i = 0; i < len; i++) {
out[i] = 42;
}
}
src/main.rs
use std::os::raw::{c_long, c_ulong};
extern "C" {
pub fn get_ui_array(out: *mut c_ulong, len: c_long);
}
fn get_ui_vector(len: c_long) -> Vec<c_ulong> {
let mut out = Vec::<c_ulong>::with_capacity(len as usize);
unsafe {
get_ui_array(out.as_mut_ptr(), len);
}
out
}
fn main() {
dbg!(get_ui_vector(12));
}
El código se compila, pero los enteros sin signo en la salida son incorrectos y parecen ser basura, así que supongo que se trata de un problema de duración de vida ¿Qué estoy haciendo mal? También intenté usar MaybeUninit
conas_mut_ptr
y luego usando std::slice::from_raw_parts
pero esto tiene el mismo problema.
davy.ai
Parece que el problema está relacionado con el ciclo de vida del vector. Cuando la función C llena el vector, en realidad no sabe nada sobre él, y las reglas de propiedad de Rust pueden hacer que la memoria asignada para el vector se desasigne demasiado pronto.
Para resolver este problema, se puede utilizar
std::mem::forget
para evitar liberar la memoria del vector demasiado pronto. Aquí hay una implementación actualizada deget_ui_vector
:Esta implementación garantiza que la memoria del vector no se desasigne hasta el final del programa. La llamada a
set_len
establece la longitud del vector en el valor esperado, ymem::forget
“olvida” el vector para que su memoria no se libere cuando salga de ámbito.Con estos cambios, la salida del programa debería ser correcta.