This is the mail archive of the
gcc-bugs@gcc.gnu.org
mailing list for the GCC project.
Re: Problem with putenv() in global constructor
- From: Loren James Rittle <rittle at latour dot rsch dot comm dot mot dot com>
- To: gcc-bugs at gcc dot gnu dot org
- Date: Wed, 8 Jan 2003 20:31:26 -0600 (CST)
- Subject: Re: Problem with putenv() in global constructor
- Organization: Networks and Infrastructure Lab (IL02/2240), Motorola Labs
- References: <200301071633.h07GX8TG001946@latour.rsch.comm.mot.com>
In article <3E1B2D57.3080108@roguewave.com>, Martin Sebor writes:
>>> I found some strange putenv() function behavior when it's used in a
>>> global object (C++ code) constructor. I work on SPARC/Solaris 8
>>> with g++/gcc version 2.95.3 20010315 (release). [...]
>> This behavior is outside the scope of anything we can "fix" (unless we
>> break other global constuctor-related issues). Your report does not
>> suprise me. To be most portable, C++ programs should avoid global
>> constructors that will invoke library functions traditionally callable
>> only after main() has been invoked.
> With all respect, that seems like a pretty vague description of such
> a severe restriction -- are those functions documented anywhere?
> FWIW, the "problem" seems to be caused by the gcc runtime (2.95
> through 3.2) and does not appear to be C++ specific (gcc exhibits
> the same behavior for functions declared with the __attribute__
> ((constructor)) extension). On the same system, SunPro handles
> fine call to putenv() in ctors of global objects.
Hi Martin,
In light of your feedback, I should like to change my statement:
This behavior is outside the scope of anything we can "fix" (unless we
break other global constuctor-related issues). Your report does not
suprise me. To be most portable, C++ programs should avoid global
objects whose related constructors will invoke functions with unknown
implementation. (i.e. I'd rather write this portability guideline
even stronger/more restrictive than have to answer your good question. ;-)
I would rewrite your FWIW as: ``The failure is caused by the ELF
run-time program loader (nothing gcc controls) in conjunction with the
ELF features used by gcc to register global object constructors (we
control this but we follow the spec AFAIK) in conjunction with the
implementation of the Solaris libc (nothing gcc controls) when it is
statically-linked against the application (i.e. ELF image setup
ordering is not operative to sort out ordering issues between libc and
the dependent application in this case).'' I suppose that gcc could
go back to ignoring the ELF init/fini features and use collect2 on ELF
platforms but I doubt that is a productive change. BTW, have you
tested SunPro in this case with a static link? If it uses the same
ELF features as gcc, then I'd be willing to bet that it will fail in
the same manner as gcc. BTW, I left this analysis out of my original
statement since portability guidelines don't assign blame and neither am I...
Here is the test case I infer from the original poster:
#include <stdlib.h>
class A { public: A() { putenv ("A=B"); } };
A a;
main() {}
It runs fine for me on Solaris 2.6 with a shared link with ~gcc
2.95.3. Crashes in putenv()/find() for stated reason above (unless my
analysis is buggy and, of course, it might be) with a static link.
Here is the exact change to g++ that caused the issue reported: at
some point, quite some time ago (in 1998, between 2.7 and 2.95), g++
for ELF targets changed from __main()-fired constructors (where __main
was called as a secret step compiled into user's main()) to ELF-style
constructors which may fire before other system startup code perhaps
required to run before libc will be completely stable (some libc
implementations use init checks internally, some rely on explicit
startup code calls; the standard is silent on this matter of which
style must be used and has a classic punt on timing/ordering; gcc
explicitly documents that we do not control the libc implementation;
thus my comment about "outside our scope"). I make no value judgment
on the change other than I know it fixed other C++ compliance issues
related to constructors and un/loading ELF shared images; either way,
it is now a fact of life in multiple shipped versions of gcc. You
will note that I didn't blame Sun's libc for this problem just that we
can't fix it without breaking/changing other behavior.
A number of questions could be raised: Does SunPro use *standard* ELF
format hooks to register constructors as gcc does on ELF platforms?
Does it use some trick to ensure that (e.g.) malloc()/putenv() is
usable before other ELF constructors are run (when you use dependent
shared libraries you get such ordering in the ELF run-time loader)?
Is that trick available to gcc? Does Sun document where global C++
constructors must run in the startup process? What if a standard
dicates otherwise? At the time g++ switched constructors methods
(years ago), did the change violate a system ABI? Again, what if the
language standard says otherwise or allows otherwise by omission of
confining statements?
People that want to write the most portable C++ programs have to know
all about this. ELF's ability to handle such ordering of
module/library dependencies almost removes the issue but not
everything is an ELF or shared.
Regards,
Loren