We had so many of these issues that we ended up LD_PRELOAD-ing patch getenv / setenv / putenv
C stdlib isn't threadsafe and even safe Rust didn't save us
81–90 of 370 posts
Re: C stdlib isn't threadsafe and even safe Rust didn't save us
#82Earlier quoted context omitted.
Yeah, setenv should probably just not exist, and environment variables should be only set when spawning new processes.
The problem is that applications sometimes need to set environment variables which will be read by libraries in the same process. This is safe to do during startup, but at no later times. Ideally all libraries which use environment variables should have APIs allowing you to override the env variables without calling setenv(), but that isn't always the case.
No, the problem is that libraries try to do this at all. Libraries should just have those APIs you mention, and not touch env vars, period. If you, the library user, really want to use env vars for those settings, you can getenv() them yourself and pass them to the library's APIs.
Obviously we can't change history; there are libraries that do this anyway. But we should encourage library authors to (in the future) pretend that env vars don't exist.
Re: C stdlib isn't threadsafe and even safe Rust didn't save us
#83Re: C stdlib isn't threadsafe and even safe Rust didn't save us
#84Earlier quoted context omitted.
They did, it's called core. But it assumes no operating system at all, and environment variables require an operating system.
> and environment variables require an operating system Is that true? It's just a process global string -> string map, that can be pre-loaded with values before the process starts, with a copy of the current state being passed to any sub-process. This could be trivially implemented with batch processing/supervisory programs.
Re: C stdlib isn't threadsafe and even safe Rust didn't save us
#85I always thought this was kinda foolish: your configuration method is a flat-namespace basked of stringly-typed values. The perils of getenv()/setenv()/environ are also, I think, a great argument against using env vars for configuration.
Sure, there aren't always great, well-supported options out there. I prefer using a configuration file (you can have templated config and a system that fills in different values for e.g. dev/stage/prod), and I'll usually use YAML, despite its faults and gotchas. There are probably better configuration file formats, but IMO YAML is still significantly better than using env vars.
Re: C stdlib isn't threadsafe and even safe Rust didn't save us
#86Earlier quoted context omitted.
Why requiring unsafe when the std implementation could take care of the synchronisation?
Because the std implementation can not force synchronisation on the libc, so any call into a C library which uses getenv will break... which is exactly what happened in TFA: `openssl-probe` called env::set_var on the Rust side, and the Python interpreter called getenv(3) directly.
Re: C stdlib isn't threadsafe and even safe Rust didn't save us
#87Re: C stdlib isn't threadsafe and even safe Rust didn't save us
#88I wonder why it is so hard for Rust to implement its own safe stdlib independent of C.
Linux is an unusual platform in that it allows you to call into it via assembly. Most other platforms require you to go through libc to do so. It's not really in Rust's hands.
*BSD allows it too, or used as of 2022.
What is unusual about Linux is that it guarantees a syscall ABI, meaning that if you follow it, you can make a system call "portably" across "any" version of Linux.
Re: C stdlib isn't threadsafe and even safe Rust didn't save us
#89But really, I don't understand why a sensitive security-related library would implicitly use an unsafe function like setenv().
Re: C stdlib isn't threadsafe and even safe Rust didn't save us
#90Earlier quoted context omitted.
The man page says: > POSIX.1 does not require setenv() or unsetenv() to be reentrant. A non-reentrant function cannot be thread safe. In general (for POSIX, libc and many other libraries: if the docs do not explicitly say "this function is thread safe" they are not).
It's time to move beyond this attitude and make things safe by default. For example, Solaris has a safer version of setenv(). "It is ridiculous that this has been a known problem for so long. It has wasted thousands of hours of people's time, either debugging the problems, or debating what to do about it. We know how to fix the problem." https://www.evanjones.ca/setenv-is-not-thread-safe.html
30 years after these decisions were made, most sensible people do single threaded GUIs anyway (that is, all calls to the windowing API come from a single thread, and all redraws occur synchronously with respect to that thread; this does not block the use of threads functioning as workers on behalf of the GUI, but they are not allowed to make windowing API calls themselves).
Consequently, the overhead present in the win32 API is basically just dead-weight, there to make sure that "things are safe by default".
There's a design lesson here for everyone, though precisely what it is will likely still be argued about.