Historia de la pregunta:
Rust fue diseñado originalmente como un lenguaje cuyo enfoque principal es la seguridad de la memoria. Sin embargo, en algunas tareas —por ejemplo, al trabajar con FFI o asignadores de bajo nivel— es necesario utilizar punteros crudos y gestionar la memoria dinámica manualmente. Estas tareas se encuentran tanto en la programación de sistemas como en la optimización del rendimiento. Por lo tanto, es importante saber cómo Rust previene fugas, punteros colgantes y el uso después de la liberación.
Problema:
Los punteros crudos (*const T, *mut T) no están integrados en el sistema de propiedad y control de referencias de Rust: pueden apuntar a memoria no válida, ser liberados incorrectamente o no liberarse en absoluto. Un error al trabajar con ellos puede llevar a UB (comportamiento indefinido), bloqueos, vulnerabilidades de seguridad o fugas de memoria.
Solución:
En lugar de punteros crudos, se recomienda utilizar tipos seguros: Box, Rc, Arc, y para referencias temporales —referencias de préstamo. Si es inevitable utilizar punteros crudos (por ejemplo, para trabajar con una API de C), todo el trabajo se envuelve en bloques unsafe, se organiza cuidadosamente el Drop, y en la medida de lo posible, se utilizan crates como NonNull. Otra técnica es el uso de envoltorios RAII y la minimización del ciclo de vida del puntero.
Ejemplo de código:
fn allocate_in_heap() -> Box<i32> { Box::new(100) } // la memoria se liberará automáticamente // con puntero crudo unsafe fn leak_memory() { let ptr = libc::malloc(4) as *mut i32; if !ptr.is_null() { *ptr = 42; // libc::free(ptr); // si se olvida liberar — ¡fuga! } }
Características clave:
Drop y el enfoque RAII protegerán contra la mayoría de las fugas¿Garantiza Box la limpieza automática de todos los valores anidados al eliminar Box?
Sí, al eliminar Box<T>, el destructor llama a la limpieza primero de la envoltura y luego de manera recursiva —de todos los datos anidados dentro (hasta los elementos de Vec o otros Box dentro de la estructura T).
¿Se puede pasar un puntero crudo de estructura de forma segura a través de varias funciones sin riesgo de obtener uso después de liberar?
No, el puntero crudo no lleva la información sobre el tiempo de vida del objeto. El compilador no puede verificar la seguridad, por lo que la responsabilidad recae totalmente en el desarrollador: si el objeto se libera, el puntero crudo apuntará a la nada.
Si usamos manualmente free o drop_in_place, ¿puede Rust llamar a Drop dos veces para la misma dirección?
Sí, si después de la liberación manual se deja otro Box/puntero que apunte a ese mismo bloque, al destruir el segundo ejemplar se llamará a Drop nuevamente, causando UB. Nunca se debe liberar manualmente aquello que es gestionado por Box, Vec y otros.
mem::forget o puntero crudo no liberadoUn programador aceptó un puntero crudo de una biblioteca C externa, no lo liberó después de usarlo o cometió un error con el tiempo de vida.
Ventajas:
Desventajas:
Se utiliza un envoltorio RAII con Drop, el puntero se encapsula a través de Box o NonNull, todo se destruye de manera segura al final del alcance.
Ventajas:
Desventajas: