ProgrammatieSysteemontwikkelaar

Leg uit hoe het systeem FFI (Foreign Function Interface) werkt in Rust. Welke vereisten en valkuilen zijn er voor een veilige aanroep van functies uit C?

Slaag voor sollicitatiegesprekken met de Hintsage AI-assistent

Antwoord

FFI in Rust maakt het mogelijk om functies aan te roepen die zijn gedefinieerd in externe bibliotheken (zoals C/C++), en om Rust-functies naar buiten te exporteren. Hiervoor wordt het sleutelwoord extern gebruikt. Vereisten:

  • Alle FFI-aanroepen moeten worden omgeven door een verklaring met unsafe;
  • De ABI (Application Binary Interface) moet overeenkomen (meestal "C");
  • Gegevens typen moeten compatibel zijn — het is belangrijk om primitieve typen met vaste groottes te gebruiken (i32, u64 enz.);
  • Geheugenbeheer — zeer voorzichtig zijn met eigendom, geheugenlekken en dubbele vrijgave.

Voorbeeld van een wrapper:

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

Een functie uit Rust exporteren voor gebruik in C kan zo:

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

Vraag met een val

Vraag: Garandeert Rust dat als je een aanroep naar een C-functie omhulld in unsafe, alles correct werkt qua threadveiligheid en het vangen van UB?

Antwoord: Nee! unsafe is een belofte aan de compiler dat je zelf garant staat voor de juistheid van alle veiligheidsvereisten (aliasing, threadveiligheid, toegang tot geheugen). Rust voert geen controles uit op de code binnen C. Bijvoorbeeld, een race condition of UB in de bibliotheekcode kan de runtime van het Rust-programma "breken". Zelfs als de Rust-code compileert, kan de daadwerkelijke uitvoering leiden tot een crash.


Verhaal

Bij een financiële dataprovider integreerde het team een C-bibliotheek via FFI, zonder de groottes van de typen te controleren. Op x86_64 werd verwacht dat long en i64 overeenkwamen, maar het bleek dat de groottes niet overeenkwamen op andere platforms — onjuiste geheugenlezing leidde tot bugs in berekeningen.

Verhaal

Een ontwikkelaar maakte een wrapper voor de C API, waarbij hij vergat om de doorgegeven pointers naar buffers in overweging te nemen. Omdat Rust het geheugen automatisch vrijmaakt, werkte de C-functie soms met al vrijgegeven geheugen, wat leidde tot crashes en fouten.

Verhaal

In een client-server product benaderde een Rust-module de C-bibliotheek zonder rekening te houden met multi-thread veiligheid. De bibliotheek was niet thread-safe, en Rust-programma's benaderden deze gelijktijdig vanuit verschillende threads, wat resulteerde in crashes en gegevensbeschadiging.