ProgrammierungSystemprogrammieringenieur / Rust Senior Developer

Was ist Unsafe Rust, wozu wird es benötigt, was sind seine Regeln und wie verwendet man unsafe-Blöcke richtig, um die Risiken zu minimieren?

Bestehen Sie Vorstellungsgespräche mit dem Hintsage-KI-Assistenten

Antwort

Unsafe Rust ist eine Erweiterung des sicheren Teilmengen von Rust, die es ermöglicht, Operationen durchzuführen, die der Compiler nicht auf die Korrektheit von Besitz, Lebensdauer und Alias überprüfen kann. Die Hauptanwendungsgebiete sind: Interaktion mit Low-Level-Bibliotheken, FFI, manuelle Speicherverwaltung, Implementierung von Abstraktionen, die nicht in das Modell des sicheren Rust passen.

Hauptmerkmale von unsafe:

  • Zur Verwendung muss der Block explizit deklariert werden: unsafe { ... } oder die Funktion: unsafe fn some_func()
  • In einem unsafe-Block sind unsichere Operationen erlaubt: Dereferenzierung von raw pointers, Aufruf unsicherer Funktionen und Methoden, Zugriff auf unions, statisch veränderbare Variablen, Implementierung von Methoden unstrukturierten Speichers
  • Die Verwendung von unsafe macht nicht den gesamten Code im Block unsicher für die gesamte Sprache — es wird nur manuell zur Garantierung der Korrektheit verpflichtet.

Beispiel:

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

Fangfrage

Ist der Code innerhalb eines unsafe-Blocks vollständig unsicher und nicht vom Compiler überprüfbar, oder wendet der Compiler weiterhin die Regeln des Borrow Checkers und andere Prüfungen an?

Antwort: Nein, innerhalb eines unsafe-Blocks überprüft der Compiler weiterhin viele Regeln von Rust (zum Beispiel Typisierung, Besitzregeln, Syntax), erlaubt jedoch nur die Aktionen, die sonst nicht zulässig sind. Man kann den Borrow Checker nicht vollständig deaktivieren!

Beispiel:

let mut x = 0; let r1 = &mut x as *mut i32; // Verboten: let r2 = &mut x as *mut i32; // selbst innerhalb unsafe treten Fehler auf, wenn die Mutabilität verletzt wird

Beispiele für reale Fehler aufgrund von Unkenntnis der Feinheiten des Themas


Geschichte

In einer asynchronen Dateibibliothek wurde ein raw pointer zur Steuerung des Puffers verwendet, aber es wurde vergessen, die Lebensdauer des Puffers korrekt zu verfolgen. Infolgedessen wurde der Pointer beim Schließen der Datei „hängend“ und der Zugriff führte zu einem undefined behavior (der unsafe-Bereich schützte nicht vor use-after-free).


Geschichte

In einer eigenen Implementierung einer Vec-ähnlichen Struktur erweiterte der Programmierer manuell den Puffer über unsafe. Ein Offsetfehler führte zu einer fehlerhaften Kopie von Elementen und Datenkorruption, da Alignment und Layout der Typen nicht berücksichtigt wurden.


Geschichte

In einem Thread-Handle wurde ein statischer veränderbarer Pointer (static mut) ohne angemessene Synchronisation verwendet. Dadurch trat im Mehrbenutzermodus zufällig ein Data Race auf, das zu sporadischen Abstürzen der Anwendung führte, die nur durch Fuzzing erfasst wurden.