views:

569

answers:

3

A co-worker just asked me if it was safe to use getenv() in static initializers, that is, before main(). 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  A: 

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

ChrisW
This answer sounds right to me, but do you have any citations from a standard or a widely respected document ala Stevens? I already believe this to be so, I'm trying to prove that it is required.
Don Wakefield
It's implied by Stevens: the process begins before your initializers are run.
ChrisW
Yah, I guess 'implied' is the best I'm gonna get for this set of circumstances.
Don Wakefield
+4  A: 

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

codelogic
Thanks, I wasn't aware of that switch.This still falls under the category of "try it and see what happens", which translates to "try it and see what happens *this time*". I'm still hoping for some cites.
Don Wakefield
Okay, uncle! ;^)~Your additional edits are more 'just so' datapoints, but they're sufficiently detailed, germane to my environment and impressive that I'm picking your answer.At least until somebody can quote some obscure section of a standards doc!
Don Wakefield
+4  A: 

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.

Tall Jeff
In C, there is no guarantee about anything happening in any order before main() starts. In C++, there might be some guarantees, somewhere, but I think you'd be hard-pressed to find them. That environ needs to be set up early (so the dynamic loader can use it too) is indubitable but not guaranteed.
Jonathan Leffler