Bug 863 - __libc_start_main() resets __environ
Summary: __libc_start_main() resets __environ
Status: RESOLVED DUPLICATE of bug 727
Alias: None
Product: glibc
Classification: Unclassified
Component: libc (show other bugs)
Version: 2.3.3
: P2 normal
Target Milestone: ---
Assignee: GOTO Masanori
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2005-04-20 19:52 UTC by Craig
Modified: 2005-09-27 05:53 UTC (History)
1 user (show)

See Also:
Host: any
Target: any
Build: any
Last reconfirmed:
Project(s) to access:
ssh public key:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Craig 2005-04-20 19:52:19 UTC
The INIT_ARGV_and_ENVIRON macro defined in sysdeps/generic/bp-start.h
(and called from __libc_start_main()) sets the global __environ
pointer.  Unfortunately, this overrides any changes to __environ that
were made by __add_to_environ() in sysdeps/generic/setenv.c.  This
causes problems for dynamically linked libraries whose _init()
function calls setenv(), since the dynamic library initialization
occurs before __libc_start_main() runs.  (Actually, it looks like
__environ may be uninitialized if setenv() is called from a dynamic
library intializer, but I'm not certain.)  This is with glibc source
code version 2.3.3 (unmodified, straigt from the tar file).

Here's an example program which illustrates this behavior:

-- envlib.cc:

#include <stdlib.h>

struct PreEnvlibSetter {
  PreEnvlibSetter() { setenv("ENVLIB_PRE", "1", 1); }
};
static PreEnvlibSetter dummy1;    // gets called before main() is called

struct PostEnvlibSetter {
  PostEnvlibSetter() { setenv("ENVLIB_POST", "1", 1); }
};
void EnvlibSetter() {
  PostEnvlibSetter dummy2;        // gets called after main() is called
}

-- env.cc:

#include <stdio.h>
#include <stdlib.h>

struct PreEnvSetter {
  PreEnvSetter() { setenv("ENV_PRE", "1", 1); }
};
static PreEnvSetter dummy3;    // gets called before main() is called

struct PostEnvSetter {
  PostEnvSetter() { setenv("ENV_POST", "1", 1); }
};
void EnvSetter() {             // gets called after main() is called
  PostEnvSetter dummy4;
}

void EnvlibSetter();

int main(int argc, char** argv) {
  EnvlibSetter();
  EnvSetter();

  printf("envlib-pre: %s\nenvlib-post: %s\nenv-pre: %s\nenv-post: %s\n",
         getenv("ENVLIB_PRE"), getenv("ENVLIB_POST"),
         getenv("ENV_PRE"), getenv("ENV_POST"));
  return 0;
}

--

When I compile in one unit, everything works as I'd expect:
% gcc env.cc envlib.cc -lstdc++
% ./a.out
envlib-pre: 1
envlib-post: 1
env-pre: 1
env-post: 1

But when I put envlib into a shared library, ENVLIB_PRE doesn't "stick":
% gcc -shared envlib.cc -oenvlib.so
% gcc env.cc `pwd`/envlib.so -lstdc++
% ./a.out
envlib-pre: (null)
envlib-post: 1
env-pre: 1
env-post: 1

Also:
% gcc --version
gcc (GCC) 3.2.2 20030222 (Red Hat Linux 3.2.2-5)
Copyright (C) 2002 Free Software Foundation, Inc.

craig
Comment 1 Ulrich Drepper 2005-09-27 05:53:46 UTC

*** This bug has been marked as a duplicate of 727 ***