On Windows you can use GetEnvironmentVariable/SetEnvironmentVariable (on XP and later), which do implement some locking and doesn't run into this issue because GetEnvironmentVariable copies the data out into a caller-supplied buffer. getenv_s was a nice effort, but it failed.
I don't really understand why other languages such as Go and Rust decided to call the weird POSIX API rather than implementing their own API, which matches the semantics they expect. In cross platform C you'll be stuck with the outdated POSIX API design, but there's no reason why other languages should accept those same limitations.
We're not running on PDP-11s anymore. You can afford a thread-safe hash map in your standard library. Ignore the limitations of the old C library. Twenty years ago, Microsoft released a better API, keep the crashy old API with tons of deprecation warnings (hell, add a compiler flag --enable-broken-c-api-designs) and just provide new APIs that are actually usable in modern programming environments.
Rust's stdlib's API is completely safe here. On Windows[1], it uses the GetEnvironmentVariable/SetEnvironmentVariable API, which as you noted doesn't have this problem. On Unix[2], it maintains its own RwLock to provide synchronisation. Additionally, Rust's API only gives out copies of the data, it never gives you a pointer to the original.
The problem comes when you do FFI on *nix systems, because those foreign functions may start making unsynchronised calls to getenv/setenv.
Once you start to provide C interoperability, it is inevitable because C programs still rely on that broken API and many users would expect that Rust will give the same time zone as C. And with an exception of Windows, that API is often the single existing API throughout the entire system.
Go likes to ignore edge cases ("all file names are UTF-8 and if they aren't then we'll just pretend they are") to make it easier to write code, so I'm not very surprised that it got caught in a POSIX related crash here.
It's hard to tell if Microsoft altered the source code since, but the leaked XP source code (https://github.com/tongzx/nt5src/blob/master/Source/XPSP1/NT...) doesn't seem to do any getenv() calls for DNS lookups. The specific bug that started all this nonsense only triggers on (specific) Unix implementations. Unfortunately, Go opts to call the POSIX methods rather than GetEnvironmentVariable/SetEnvironmentVariable on Windows, so I suppose it's still possible that somewhere in the chain this bug gets triggered by Go code.
I'm saying that on UNIX, the C standard library provides the OS API, while on Linux the OS API can be accessed directly via syscall numbers (which are stable). But on Linux `getenv()` is still not an OS API, it's provided by libc (musl or glibc, both provide POSIX APIs as well as the ISO C standard library functions and some other extensions and syscall wrappers).
> On non-UNIX platforms stuff like getenv() belongs to the specific compiler C library, not the OS API, hence why Windows doesn't use it.
Linux isn't a UNIX, and non-POSIX compliant Linux distributions exist. getenv() is still part of the C library, not the OS API, yet Linux distributions still use it. So that's not the only reason why Windows doesn't use it. It's more because Windows design wasn't originally POSIX-compatible (some POSIX wrappers got added with Windows NT) and MS designed their own API.
I don't really understand why other languages such as Go and Rust decided to call the weird POSIX API rather than implementing their own API, which matches the semantics they expect. In cross platform C you'll be stuck with the outdated POSIX API design, but there's no reason why other languages should accept those same limitations.
We're not running on PDP-11s anymore. You can afford a thread-safe hash map in your standard library. Ignore the limitations of the old C library. Twenty years ago, Microsoft released a better API, keep the crashy old API with tons of deprecation warnings (hell, add a compiler flag --enable-broken-c-api-designs) and just provide new APIs that are actually usable in modern programming environments.