Sort of… the problem is that being “safe” is infectious; everything marked safe has to be safe to use together. If I’m publishing a crate, I want to be able to say “my crate plus the standard library is safe: you can’t break the safety rules without an unsafe block”, and we want to ensure that this is reasonable.
For example, suppose I’m the author of the time crate, and I want it to be safe combined with the standard library. https://doc.rust-lang.org/time/time/fn.at.html uses localtime_r to convert a time to the local timezone. I have to mark time::at unsafe; otherwise, you can write “safe” programs which segfautt.
Or suppose I want to write a safe crate which wraps GTK; the initialization function has to be unsafe because the user has to promise they won’t call set_var at the same time.
Basically, I think making set_var safe draws the line for safety at the wrong place; being able to write safe wrappers for C code seems more valuable than being able to modify the C environment in safe code.
(Another possibility to get around this mess would be to build a copy of the environment in the Rust standard library: we could have a set_var function which is threadsafe, but doesn’t modify the C environment. Probably more confusing than useful, though.)
Oh, and error_string in the standard library also needs to lock the environment. The number of places we screw this up in the standard library is a good indication that other libraries will run into trouble, especially given that it’s impossible to fix code outside the standard library to take the Rust environment lock.