Bug 38812 - gcj-built executables don't run after strip (libgcj erroneously references _environ)
Summary: gcj-built executables don't run after strip (libgcj erroneously references _e...
Status: RESOLVED WONTFIX
Alias: None
Product: gcc
Classification: Unclassified
Component: libgcj (show other bugs)
Version: 4.3.2
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2009-01-12 11:29 UTC by Peter Keller
Modified: 2016-09-30 22:51 UTC (History)
6 users (show)

See Also:
Host:
Target: *-*-darwin*
Build:
Known to work:
Known to fail:
Last reconfirmed: 2010-05-17 12:53:59


Attachments
Output from gcj -v (1.11 KB, text/plain)
2009-01-12 11:30 UTC, Peter Keller
Details
Preprocessor output (165 bytes, text/plain)
2009-01-12 11:31 UTC, Peter Keller
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Peter Keller 2009-01-12 11:29:08 UTC
On OS X 10.5 (Leopard), compile/link HelloWorld:

  class HelloWorld {
    static public void main( String args[] ) {
      System.out.println( "Hello World!" );
    }
  }

as follows:

  gcj --main=HelloWorld HelloWorld.java

Then strip and run a.out:

  strip a.out
  ./a.out
    dyld: Symbol not found: _environ
      Referenced from: /public/sw/gcc-4.3.2/Darwin-i386-buildhost2/lib/libgcj.9.dylib
      Expected in: flat namespace

    Trace/BPT trap

Applying the following patch and rebuilding libgcj.9.dylib fixes the problem:

--- libjava/java/lang/natPosixProcess.cc.orig   2009-01-08 17:06:14.000000000 +0000
+++ libjava/java/lang/natPosixProcess.cc        2009-01-09 21:13:34.000000000 +0000
@@ -54,7 +54,6 @@
 using gnu::java::nio::channels::FileChannelImpl;
 using namespace java::lang;
 
-extern char **environ;
 
 static char *
 new_string (jstring string)
@@ -371,8 +370,16 @@
     if (pid_tmp == 0)
        {
          // Child process, so remap descriptors, chdir and exec.
-         if (envp)
-            environ = env;
+         if (envp) {
+              for ( char *p, *e = *env; *e; e++ ) {
+                 p=index(e, '=');
+                 if ( p ) {
+                    *p = '\0';
+                    setenv (e, p+1, 1);
+                    *p = '=';
+                 }
+              }
+          }
 
          // We ignore errors from dup2 because they should never occur.
          dup2 (outp[0], 0);

More information: the OS X man page for environ(7) says:

Shared libraries and bundles don't have direct access to environ, which is only available to the loader ld(1) when a complete program is being linked.
Comment 1 Peter Keller 2009-01-12 11:30:50 UTC
Created attachment 17075 [details]
Output from gcj -v
Comment 2 Peter Keller 2009-01-12 11:31:41 UTC
Created attachment 17076 [details]
Preprocessor output
Comment 3 Andrew Pinski 2009-01-13 01:03:10 UTC
Confirmed, though your patch is not portable really.
Comment 4 Peter Keller 2009-01-13 11:26:12 UTC
Thanks for confirming the problem. I know that what I did isn't particularly portable (although it would be fine on the systems that I work with). I vaguely remember something about setenv not being available on Solaris, but I haven't worked with Solaris for several years now.

I'm hoping that someone with more experience than me of libgcj development and the range of supported OS's can use my information to submit a more robust fix. I'll keep an eye on this bug and help out if I can.
Comment 5 Francois-Xavier Coudert 2010-05-17 12:53:59 UTC
On Mac OS X (all versions), the correct fix is to use _NSGetEnviron() instead of extern variable environ, and to include <crt_externs.h>. Example of use:

#include <stdlib.h>
#include <string.h>
#include <crt_externs.h>

int main (void)
{
  // Instead of: extern char **environ;
#define environ (*_NSGetEnviron())

  char **env = malloc (3 * sizeof(char *));
  env[0] = strdup ("VAR1=this is variable one");
  env[1] = strdup ("PATH=/dev/null");
  env[2] = NULL;
  environ = env;

  system ("/usr/bin/env");
  return 0;
}


(see http://www.gnu.org/software/gnulib/manual/html_node/environ.html)



So, a possible patch (protecting target-specific code with #idef's; I don't know if that's the style libjava maintainers would like best) is:

Index: java/lang/natPosixProcess.cc
===================================================================
--- java/lang/natPosixProcess.cc	(revision 159481)
+++ java/lang/natPosixProcess.cc	(working copy)
@@ -54,7 +54,12 @@
 using gnu::java::nio::channels::FileChannelImpl;
 using namespace java::lang;
 
+#ifdef __APPLE__
+#include <crt_externs.h>
+#define environ (*_NSGetEnviron())
+#else
 extern char **environ;
+#endif
 
 static char *
 new_string (jstring string)
Comment 6 Eric Gallager 2015-06-11 00:15:59 UTC
There's also some places where environ is used as an extern variable in libiberty that would need similar fixes; specifically in pex-unix.c and xmalloc.c.
Comment 7 Eric Gallager 2015-09-03 18:03:39 UTC
(In reply to Eric Gallager from comment #6)
> There's also some places where environ is used as an extern variable in
> libiberty that would need similar fixes; specifically in pex-unix.c and
> xmalloc.c.

...and it turns out that that is bug 63758, for reference... (sorry for the digression; I hadn't seen the other one previously...)
Comment 8 Peter Keller 2016-02-05 11:17:24 UTC
(In reply to Eric Gallager from comment #7)
> (In reply to Eric Gallager from comment #6)
> > There's also some places where environ is used as an extern variable in
> > libiberty that would need similar fixes; specifically in pex-unix.c and
> > xmalloc.c.
> 
> ...and it turns out that that is bug 63758, for reference... (sorry for the
> digression; I hadn't seen the other one previously...)

... which was marked as RESOLVED/FIXED on 2015-12-07. It would be great if someone committed a fix for this bug, using the same method.
Comment 9 Andrew Pinski 2016-09-30 22:51:12 UTC
Closing as won't fix as libgcj (and the java front-end) has been removed from the trunk.