ProgrammazioneSviluppatore Backend

Come funziona il meccanismo degli slice in Rust, quali tipi di slice esistono, come viene garantita la sicurezza e cosa succede quando si tenta di uscire dai limiti dello slice?

Supera i colloqui con l'assistente IA Hintsage

Risposta

Lo slice in Rust è una rappresentazione dinamica di una parte di una collezione i cui elementi sono disposti in memoria in modo consecutivo. Un esempio tipico di slice è &[T] o &mut [T]. Gli slice non possiedono i dati, ma fanno riferimento a un buffer esterno. Tutti gli slice hanno una lunghezza, archiviata insieme al riferimento.

Tipi principali:

  • &[T] — slice immutabile
  • &mut [T] — slice mutabile
  • Per le stringhe: &str (di fatto — slice di byte, sempre UTF-8 valido)

La sicurezza degli slice è garantita a livello di compilatore e runtime: qualsiasi tentativo di accedere a un elemento al di fuori dei limiti dello slice provocherà un panic durante l'esecuzione, non si verificherà alcun errore irreparabile in memoria come in C/C++.

Esempio:

let v = vec![1, 2, 3, 4, 5]; let s: &[i32] = &v[1..4]; // slice che fa riferimento agli elementi 2, 3, 4 println!("{:?}", s); // [2, 3, 4] // s[3]; // panic! (uscita dai limiti)

Domanda trabocchetto

Gli slice possono essere vuoti? Qual è la differenza tra uno slice vuoto e None?

Risposta: Sì, gli slice possono essere vuoti (&[]), ciò significa un riferimento a una parte di dati con lunghezza zero, ma non è equivalente a None. Uno slice vuoto è sicuro da usare, mentre Option<&[T]> serve a distinguere se "c'è davvero uno slice".

Esempio:

let s: &[i32] = &[]; assert!(s.is_empty()); // Option<&[i32]> è usato se lo slice potrebbe non esistere affatto.

Esempi di errori reali a causa della mancanza di conoscenza delle sottigliezze dell'argomento


Storia

In un grande servizio di logging, uno sviluppatore ha preso uno slice su un intervallo calcolato dinamicamente dai dati dell'utente. Con un calcolo errato dello slice (ad esempio, se start > end o se end > len), il codice ha funzionato nei test, ma in produzione ha provocato un "panic" e ha arrestato il processo durante i picchi di carico.


Storia

In una libreria interna di hash concurrent, hanno utilizzato &mut [T] e parallelamente diversi thread prendevano diversi slice dello stesso array. Un thread modificava lo slice, mentre un altro utilizzava un altro slice sulla stessa memoria. Il programma si compilava, ma a causa di una divisione errata potevano verificarsi UB tramite codice non sicuro (utilizzando unsafe), se gli slice si sovrapponevano comunque.


Storia

In un parser di pacchetti di rete di sistema, è stato creato uno slice in modo non sicuro (puntatore raw e from_raw_parts). Lo sviluppatore ha dimenticato di controllare la correttezza della lunghezza del pacchetto in ingresso. Di conseguenza, un tentativo di lettura oltre i limiti ha portato all'arresto dell'applicazione e a una vulnerabilità (potential OOB access), che poteva essere evitata con l'uso corretto degli slice sicuri.