ProgramaciónDesarrollador de sistemas

Explique cómo funciona el system FFI (Foreign Function Interface) en Rust. ¿Cuáles son los requisitos y las trampas para llamar de manera segura a funciones de C?

Supere entrevistas con el asistente de IA Hintsage

Respuesta

FFI en Rust permite llamar a funciones declaradas en bibliotecas externas (por ejemplo, C/C++) y exportar funciones de Rust hacia afuera. Para esto se utiliza la palabra clave extern. Requisitos:

  • Todas las llamadas FFI deben estar envueltas en una declaración con unsafe;
  • El ABI (Application Binary Interface) debe coincidir (generalmente "C");
  • Los tipos de datos deben ser compatibles: es importante utilizar primitivos de tamaños fijos (i32, u64, etc.);
  • Gestión de memoria: tener mucho cuidado con la propiedad, pérdidas de memoria y doble liberación.

Ejemplo de envoltura:

extern "C" { fn abs(input: i32) -> i32; } fn main() { unsafe { println!("{}", abs(-5)); } }

Para exportar una función de Rust para su uso en C se puede hacer así:

#[no_mangle] pub extern "C" fn sum(a: i32, b: i32) -> i32 { a + b }

Pregunta capciosa

Pregunta: ¿Garantiza Rust que si se envuelve la llamada a la función C en unsafe, funcionará correctamente en términos de seguridad de hilos y captura de UB?

Respuesta: ¡No! unsafe es una promesa al compilador de que usted se asegura de que todos los requisitos de seguridad sean correctos (aliasing, seguridad de hilos, acceso a memoria). Rust no realiza comprobaciones del código dentro de C. Por ejemplo, una condición de carrera o UB en el código de la biblioteca puede "romper" el tiempo de ejecución del programa Rust. Incluso si el código Rust se compila, la ejecución real puede llevar a una falla.


Historia

En un proveedor de datos financieros, el equipo integró una biblioteca C a través de FFI, sin verificar los tamaños de los tipos. En x86_64 se esperaba que long e i64 coincidieran, pero resultó que los tamaños no coincidían en otras plataformas: una lectura incorrecta de la memoria llevó a errores en los cálculos.

Historia

Un desarrollador creó una envoltura para la API de C, olvidando los punteros de los buffers pasados. Dado que Rust liberaba automáticamente la memoria, la función C a veces trabajaba con memoria ya liberada, lo que causaba fallos y caídas.

Historia

En un producto cliente-servidor, el módulo Rust accedía a la biblioteca C sin considerar la seguridad de múltiples hilos. La biblioteca no era segura para hilos, y los programas Rust accedían a ella desde diferentes hilos simultáneamente, lo que resultó en bloqueos y corrupción de datos.