I looked in Stevens, and in the Posix Programmer's Guide, and the best I can find is
An array of strings called the enviroment is made available when the process begins. This array is pointed to by the external variable
environ
, which is defined as:
extern char **environ;
It's that environ variable that has me hesitating. I want to say
-The calling process/shell has already allocated the block of null terminated strings
-the 'external' variable environ
is used as the entry point by getenv().
-ipso facto feel free to call getenv() within a static initializer.
But I can't find any guarantee that the 'static initialization' of environ precedes all the other static initialization code. Am I overthinking this?
On my platform (AMD Opteron, Redhat 4, GCC 3.2.3), setting LD_DEBUG shows that environ gets set before my static initializers are called. This is a nice thing to know; thanks, @codelogic. But it is not necessarily the result I'd get on all platforms.
Also, while I agree intuitively with @ChrisW on the behavior of the C/C++ runtime library, this is just my intuition based on experience. So anyone who can pipe up with a quote from someplace authoritative guaranteeing that environ is there before static initializers are called, bonus points!
getenv need not be thread-safe; it is a read-only function and will not break your code. You just can't be sure the value you get is the most recent value, and you should not change the value returned by getenv (this, yes, can violate the runtime environment).
getenv(String name) method gets the value of the specified environment variable. An environment variable is a system-dependent external named value. Environment variables should be used when a global effect is desired, or when an external system interface requires an environment variable (such as PATH).
If the varname is not found, getenv() returns a NULL pointer. The returned value is NULL if the given variable is not currently defined.
The C++ standard doesn't protect us from this happening - it doesn't even acknowledge the existence of threads (this is C++98 we're talking about). So keep this in mind: such code is not thread safe - you can not assume that in the presence of multiple threads the function static variable will be constructed only once.
I think you can run your program with LD_DEBUG set to see the exact order:
LD_DEBUG=all <myprogram>
EDIT: If you look at the source code of the runtime linker (glibc 2.7), specifically in files:
you will see that argc, argv and environ (alias for __
environ) are set before any global constructors are called (the init functions). You can follow the execution starting right from _start, the actual entry point (start.S). As you've quoted Stevens "An array of strings called the enviroment is made available when the process begins", suggesting that environment assignment happens at the very beginning of the process initialization. This backed by the linker code, which does the same, should give you sufficient peace of mind :-)
EDIT 2: Also worth mentioning is that environ is set early enough that even the runtime linker can query it to determine whether or not to output verbosely (LD_DEBUG).
Given that both the environment setup and the invoking of the static initializers are functions that the language run-time has to perform before main() is invoked, I am not sure you will find a guarantee here. That is, I am not aware of a specific requirement here that this has to work and that the order is guaranteed prior to main() in, say, the ANSI language and library specifications or anything....but I didn't check to make sure either.
At the same time, I am not aware of a specific requirement that restricts which run-time library functions can be called from a static initializer. And, more to the point, it would feel like a run-time bug (to me) if you couldn't access the environment from one.
On this basis, I vote that I would expect this to work, is a safe assumption, and current data points seem to support this line of reasoning.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With