Is it safe to use getenv() in static initializers,

2019-04-19 13:25发布

问题:

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?

Update

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!

回答1:

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:

  • sysdeps/unix/sysv/linux/init-first.c
  • sysdeps/i386/init-first.c
  • csu/libc-start.c
  • sysdeps/i386/elf/start.S

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).



回答2:

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.



回答3:

In my experience, the C run time library is initialized before the run-time invokes the initializers of your static variables (and so your initializers may call C run time library functions).