ProgrammazioneIngegnere di sistema / Rust Senior Developer

Che cos'è Unsafe Rust, a cosa serve, quali sono le sue regole e come utilizzare correttamente i blocchi unsafe per minimizzare i rischi?

Supera i colloqui con l'assistente IA Hintsage

Risposta

Unsafe Rust è un'estensione del sottoinsieme sicuro di Rust che consente di eseguire operazioni che il compilatore non può verificare per quanto riguarda la gestione, la durata e l'aliasing. Le principali aree di utilizzo includono: interazione con librerie a basso livello, FFI, controllo manuale della memoria, implementazione di astrazioni che non rientrano nel modello di Rust sicuro.

Caratteristiche chiave di unsafe:

  • L'uso richiede di dichiarare esplicitamente un blocco: unsafe { ... } o una funzione: unsafe fn some_func()
  • All'interno di un blocco unsafe sono consentite operazioni non sicure: dereferenziazione di raw pointer, chiamata di funzioni e metodi non sicuri, accesso a union, variabili statiche mutabili, implementazione di metodi per memoria non strutturata
  • L'uso di unsafe non rende tutto il codice nel blocco pericoloso per l'intero linguaggio — si impegna solo a garantire manualmente la correttezza

Esempio:

let x: i32 = 10; let ptr: *const i32 = &x as *const i32; unsafe { println!("Valore: {}", *ptr); // dereferenziazione di raw pointer }

Domanda insidiosa

Il codice all'interno di un blocco unsafe è completamente non sicuro e non controllato dal compilatore, o il compilatore continua ad applicare le regole del borrow checker e altre verifiche?

Risposta: No, all'interno di un blocco unsafe il compilatore continua a controllare molte regole di Rust (ad esempio, tipizzazione, regole di proprietà, sintassi), ma consente di eseguire solo azioni che altrimenti non sarebbero consentite. Non è possibile disattivare completamente il borrow checker!

Esempio:

let mut x = 0; let r1 = &mut x as *mut i32; // Vietato: let r2 = &mut x as *mut i32; // anche all'interno di unsafe appariranno errori se si viola la mutabilità

Esempi di errori reali a causa della mancanza di conoscenza delle sfumature del tema


Storia

In una libreria di file asincroni è stato utilizzato un raw pointer per controllare un buffer, ma è stato dimenticato di tenere traccia correttamente della durata del buffer. Di conseguenza, alla chiusura del file, il pointer è diventato "appeso" e l'accesso ha portato a undefined behavior (la sezione unsafe non ha salvato da use-after-free).


Storia

Nella propria implementazione di una struttura simile a Vec, il programmatore ha ampliato manualmente il buffer tramite unsafe. Un errore di offset ha portato a una copia errata degli elementi e alla corruzione dei dati, poiché non sono stati considerati l'allineamento e il layout dei tipi.


Storia

In un descrittore di thread è stato utilizzato un puntatore statico mutabile (static mut) senza una corretta sincronizzazione. A causa di ciò, in modalità multithreading è emerso accidentalmente un data race, causando un crash sporadico dell'applicazione, catturato solo con fuzzing.