4 ms·
Is it possible to skip libc completely or would this introduce too many portability concerns?
by miohtama 2y ago
Is it possible to skip libc completely or would this introduce too many portability concerns?
- jcotton42 2y agoIt's not just libc, it's any C or C++ library that calls getenv or setenv.
- rerdavies 2y agoSpecifically, any C or C++ library that calls setenv (despite documentation that says that setenv is not threadsafe).
- SAI_Peregrinus 2y agoOr any multithreaded program that uses a C or C++ library that calls setenv somewhere internally, and failed to document that it does so and is thus unsuitable for use by multithreaded programs. No library does that documentation, so you can't use libraries on POSIX systems if writing multithreaded code. Or you do and hope for the best. So everyone just hopes for the best.
- rerdavies 2y agoThe documentation for setenv: Caveats: POSIX.1 does not require setenv() or unsetenv() to be reentrant. ... Interface: setenv(), unsetenv() Attribute: Thread safety Value: MT-Unsafe const:env Libraries that are thread-safe DO provide that documentation. One assumes that libraries that don't provide that documentation are not thread=safe. GnuTLS docs: The GnuTLS library is thread safe by design, meaning that objects of the library such as TLS sessions, can be safely divided across threads as long as a single thread accesses a single object.
- duped 2y agoIn general, no, because of FFI. In special circumstances, yes, but this isn't really important because the libc implementation is trivial (on all platforms that matter, envp is a char** to strings formatted as KEY=VALUE, set_env(key, value) is equivalent to allocating a new KEY=VALUE string and finding the index of a key if it exists or appending to the array). Under the hood the pointer is initialized by the loader, in a special place in executable memory. Most of the time, the loader gets the initial environment variable list by looking at argv* (try reading past the end of the null separator, you'll find the initial environment variables). It would be possible for a language to hack it such that on load they initialize their own env var set without using libc and be able to safely set/get those env vars without going through libc, and to inherit them when spawning child processes by reading the special location instead of the standard location initialized by your platforms' loader/updated by libc. But how useful is a language with FFI that's fundamentally broken since callees can't set environment variables? (probably very useful, since software that relies on this is questionably designed in the first place) If you wanted to make a bullet proof solution, you would specify the location of an envp mutex in the loaders' format and make it libc's (or any language runtime) problem to acquire that mutex. * there are platforms where this isn't true
- fch42 2y agoIn short, no - because environment variables are userland state only, you can't interact with them using system calls, the kernel doesn't keep a "canonical" copy of them on behalf of the process. So the "environment" is part of libc, and "libc's way" of interacting with it at runtime "is the way". From the syscall interface point of view ... you pass the initial env of a process when you exec(), and the kernel copies that to (userland) memory of the new process. The fact "default initialisation" can copy from the environment of the exec()'ing parent, or the fact that the kernel can "read" a process' env (see /proc/<PID>/environ) doesn't change this; the kernel needn't be "accommodating" all the possible and impossible ways how a user application may want to interact with that state there, if you mess-too-much with it, you get garbage. Sooo ... the portability wart is setenv(), because as far as the system is concerned... your "initial" env is passed to you when exec() is called, and any modification thereafter is your concern, your problem, but foremost, your choice. And choices come with taking responsibility for the ones you make.