Unsafe Rust to rozszerzenie bezpiecznego podzbioru Rust, które pozwala na wykonywanie operacji, których kompilator nie jest w stanie sprawdzić pod kątem poprawności własności, cykli życia i aliasowania. Główne obszary zastosowań: interakcja z niskopoziomowymi bibliotekami, FFI, ręczna kontrola pamięci, realizacja abstrahencji, które nie mieszczą się w modelu bezpiecznego Rust.
Kluczowe cechy unsafe:
unsafe { ... } lub funkcji: unsafe fn some_func()Przykład:
let x: i32 = 10; let ptr: *const i32 = &x as *const i32; unsafe { println!("Wartość: {}", *ptr); // dereferencja raw pointer }
Czy kod wewnątrz bloku unsafe jest całkowicie niebezpieczny i nie sprawdzany przez kompilator, czy kompilator nadal stosuje zasady borrow checkera i inne kontrole?
Odpowiedź: Nie, wewnątrz bloku unsafe kompilator nadal sprawdza wiele zasad Rust (na przykład, typizacja, zasady własności, składnia), ale pozwala na wykonywanie tylko tych działań, które w przeciwnym razie byłyby zabronione. Nie można całkowicie wyłączyć borrow checkera!
Przykład:
let mut x = 0; let r1 = &mut x as *mut i32; // Niedozwolone: let r2 = &mut x as *mut i32; // nawet wewnątrz unsafe pojawią się błędy, jeśli naruszona jest mutowalność
Historia
W asynchronicznej bibliotece plików użyto raw pointer do kontroli bufora, ale zapomniano poprawnie śledzić cykl życia bufora. W rezultacie, podczas zamykania pliku, wskaźnik stał się "wiszący" i dostęp do niego prowadził do zachowania undefined (sekcja unsafe nie uratowała przed use-after-free).
Historia
W własnej implementacji struktury podobnej do Vec programista ręcznie rozszerzał bufor za pomocą unsafe. Błąd przesunięcia doprowadził do nieprawidłowego kopiowania elementów i uszkodzenia danych, ponieważ nie uwzględniono wyrównania i układu typów.
Historia
W deskryptorze wątków użyto statycznego mutowalnego wskaźnika (static mut) bez odpowiedniej synchronizacji. Z tego powodu w trybie wielowątkowym przypadkowo wystąpił wyścig danych, prowadzący do sporadycznego awarii aplikacji, wychwytywanego tylko przez fuzzing.