GCC Bugzilla – Bug 13708
static java program crashes at startup, UTF-8 environment
Last modified: 2005-07-15 21:41:57 UTC
(Whoops, hit ENTER way too early!) The program is: public class jmisc { public static void main (String[] args) { return; } } When I compile and run the program with LANG=en_US, it works fine. When I compile and run the program with LANG=en_US.UTF-8, it segfaults in _Jv_FindClass. This worked with gcc HEAD 2004-01-08. I will do some date-searching to narrow it down. Also, I have a typescript to attach, showing the full stack trace.
Created attachment 5501 [details] typescript showing source code, gcj -v, stack trace of crash Here is a hunk of the backtrace. (gdb) backtrace #0 _Jv_FindClass(_Jv_Utf8Const*, java::lang::ClassLoader*) (name=0x0, loader=0x0) at /berman/fsf/_today_/source/gcc/HEAD/gcc/libjava/java/lang/natClassLoader.cc:507 #1 0x08070f20 in java::lang::Class::forName(java::lang::String*, bool, java::lang::ClassLoader*) (className=0x0, initialize=1 '\001', loader=0x0) at /berman/fsf/_today_/source/gcc/HEAD/gcc/libjava/java/lang/natClass.cc:81 #2 0x0807102c in java::lang::Class::forName(java::lang::String*) ( className=0x0) at /berman/fsf/_today_/source/gcc/HEAD/gcc/libjava/java/lang/natClass.cc:113 #3 0x080b5e9b in gnu.gcj.convert.UnicodeToBytes.getDefaultEncoder() () at /berman/fsf/_today_/source/gcc/HEAD/gcc/libjava/gnu/gcj/convert/UnicodeToBytes.java:49 #4 0x0808c52e in java.io.PrintStream.PrintStream(java.io.OutputStream, boolean) (this=0x2, out=0x0) at /berman/fsf/_today_/source/gcc/HEAD/gcc/libjava/java/io/PrintStream.java:118 #5 0x08084391 in java.lang.System.__U3c_clinit__U3e_() () at /berman/fsf/_today_/source/gcc/HEAD/gcc/libjava/java/lang/System.java:146 #6 0x08070b74 in java::lang::Class::initializeClass() (this=0x81ba0c0) at /berman/fsf/_today_/source/gcc/HEAD/gcc/libjava/java/lang/natClass.cc:808 #7 0x08084741 in java.lang.System.getProperty(java.lang.String) ( key=0x81ba0c0) at /berman/fsf/_today_/source/gcc/HEAD/gcc/libjava/java/lang/System.java:405 #8 0x0808716e in java.lang.VMClassLoader.getSystemClassLoader() () at /berman/fsf/_today_/source/gcc/HEAD/gcc/libjava/java/lang/VMClassLoader.java:280 #9 0x0807c1d8 in java.lang.ClassLoader.__U3c_clinit__U3e_() () at /berman/fsf/_today_/source/gcc/HEAD/gcc/libjava/java/lang/ClassLoader.java:156
I have no problems, are you sure that the compiled program is not picking up the wrong libgcj?
Subject: Re: java program crashes at startup, UTF-8 environment Well, if the compiled program is pickign up the wrong libgcj, that's still a bug in gcc HEAD, because I'm installing the compiler and running it. But I don't think that's the problem. I'm running Red Hat Linux 8 with $LANG set to "en_US.UTF-8". What system and what value of $LANG do you have on your working system?
I am also running RedHat 8 and I set LANG to be en_US.UTF-8 and it works for me: tin:~/src/gnu/gcctest>gcj jmisc.java /usr/lib/crt1.o(.text+0x18): In function `_start': : undefined reference to `main' collect2: ld returned 1 exit status tin:~/src/gnu/gcctest>gcj jmisc.java --main=jmisc tin:~/src/gnu/gcctest>./a.out tin:~/src/gnu/gcctest>echo $LANG en_US.iso885915 tin:~/src/gnu/gcctest>setenv LANG=en_US.UTF-8 tin:~/src/gnu/gcctest>gcj jmisc.java --main=jmisc tin:~/src/gnu/gcctest>!./ ./a.out tin:~/src/gnu/gcctest>gcj jmisc.java /usr/lib/crt1.o(.text+0x18): In function `_start': : undefined reference to `main' collect2: ld returned 1 exit status tin:~/src/gnu/gcctest>gcj jmisc.java -C tin:~/src/gnu/gcctest>gij jmisc
Frequently a crash like that means your linker is too old.
This works for me, try a new binutils (which is the liner and the assembler).
Subject: Re: java program crashes at startup, UTF-8 environment My linker is binutils 2.14, the stock FSF version. I just tried binutils HEAD 2004-01-15 12:43:56 UTC, and I get the same problem. Have a look at my stack trace: #0 _Jv_FindClass .. #8 java.lang.VMClassLoader.getSystemClassLoader #9 java.lang.ClassLoader.__U3c_clinit__U3e_ java.lang.ClassLoader is initializing its static 'systemClassLoader' by calling java.lang.VmClassLoader.getSystemClassLoader. VmClassLoader.getSystemClassLoader calls getProperty("java.system.class.loader"), which causes a recursive call down to _Jv_FindClass("gnu.gcj.convert.Output_UTF8"). _Jv_FindClass finds that Output_UTF8 is not in the cache, and a loader is not provided. So it attempts to use getSystemClassLoader, which is still being initialized, and hence is still null. I don't understand why this works on Andrew's system, and I haven't nailed down the gcc patch which caused it to seg fault on my system.
Subject: Re: java program crashes at startup, UTF-8 environment Here is some trace output to help illuminate the problem. I wrote a simple gdb script, which, ironically, just simulates printf debugging at some crucial points. The first trace output is with an executable made with gcc HEAD 2004-01-09 17:10:00 UTC. In the first trace output, these events occur: call _JvCreateJavaVM class initialize for java.lang.System constructor for java.io.PrintStream _Jv_Find_class call on gnu.gcj.convert.Output_UTF8 initialization of java.lang.VMClassLoader.getSystemClassLoader The second trace output is with an executable made with gcc HEAD 2004-01-15 13:08:06 UTC. In the second trace output, these events occur: call _JvCreateJavaVM initialization of java.lang.VMClassLoader.getSystemClassLoader class initialize for java.lang.System constructor for java.io.PrintStream _Jv_Find_class call on gnu.gcj.convert.Output_UTF8 In the second version, getSystemClassLoader is initialized early. getSystemClassLoader uses j.l.System, which constructs an object of type j.io.PrintStream, which calls _Jv_Find_class on gnu.gcj.convert.Output_UTF8, which attempts to use the system class loader ... which is still being initialized ... zero is returned for the "sys" pointer and a segment fault happens. (err, I just noticed I have a typo on _Jv_Find_class, sorry about that). In the first version, j.io.PrintStream gets called before the first call to getSystemClassLoader. So when getSystemClassLoader runs for the first time, it doesn't need to re-enter j.l.System, so it does not re-enter _Jv_Find_class. I would be very interested in seeing this output from Andrew's system: gdb a.out < findclass.gdbinit === trace with gcc HEAD 2004-01-09 17:10:00 UTC GNU gdb 6.0 Copyright 2003 Free Software Foundation, Inc. GDB is free software, covered by the GNU General Public License, and you are welcome to change it and/or distribute copies of it under certain conditions. Type "show copying" to see the conditions. There is absolutely no warranty for GDB. Type "show warranty" for details. This GDB was configured as "i686-pc-linux-gnu"... (gdb) (gdb) (gdb) (gdb) (gdb) (gdb) Breakpoint 1 at 0x804c3d0: file /berman/fsf/shelf/2004-01-09-17-10-00/source/gcc/HEAD/gcc/libjava/prims.cc, line 895. (gdb) >>>>(gdb) (gdb) Breakpoint 2 at 0x80859d1: file /berman/fsf/shelf/2004-01-09-17-10-00/source/gcc/HEAD/gcc/libjava/java/lang/VMClassLoader.java, line 280. (gdb) >>>>(gdb) (gdb) Breakpoint 3 at 0x8085a90: file /berman/fsf/shelf/2004-01-09-17-10-00/source/gcc/HEAD/gcc/libjava/java/lang/VMClassLoader.java, line 300. (gdb) >>>>(gdb) (gdb) Breakpoint 4 at 0x80829ee: file /berman/fsf/shelf/2004-01-09-17-10-00/source/gcc/HEAD/gcc/libjava/java/lang/System.java, line 78. (gdb) >>>>(gdb) (gdb) Breakpoint 5 at 0x808adb6: file /berman/fsf/shelf/2004-01-09-17-10-00/source/gcc/HEAD/gcc/libjava/java/io/PrintStream.java, line 97. (gdb) >>>>(gdb) (gdb) Breakpoint 6 at 0x808ad99: file /berman/fsf/shelf/2004-01-09-17-10-00/source/gcc/HEAD/gcc/libjava/java/io/PrintStream.java, line 118. (gdb) >>>>(gdb) (gdb) Breakpoint 7 at 0x808ad4c: file /berman/fsf/shelf/2004-01-09-17-10-00/source/gcc/HEAD/gcc/libjava/java/io/PrintStream.java, line 142. (gdb) >>>>(gdb) (gdb) Breakpoint 8 at 0x806ff05: file /berman/fsf/shelf/2004-01-09-17-10-00/source/gcc/HEAD/gcc/libjava/java/lang/natClassLoader.cc, line 480. (gdb) >>>>(gdb) (gdb) Starting program: /berman/home/mec.gnu/gcc/findclass/jmisc.2004-01-09-17-10-00.exe [New Thread 8192 (LWP 22233)] [Switching to Thread 8192 (LWP 22233)] Current language: auto; currently c++ break _JvCreateJavaVM break _Jv_Find_class: java.lang.reflect.Field Current language: auto; currently java break java.lang.System.<clinit>() Current language: auto; currently c++ break _Jv_Find_class: java.lang.Object Current language: auto; currently java break java.io.PrintStream.PrintStream(java.io.OutputStream, boolean) Current language: auto; currently c++ break _Jv_Find_class: java.lang.Object break _Jv_Find_class: gnu.gcj.convert.Output_UTF8 break _Jv_Find_class: java.security.Principal Current language: auto; currently java break java.lang.VMClassLoader.getSystemClassLoader Current language: auto; currently c++ break _Jv_Find_class: java.net.URL break _Jv_Find_class: java.lang.Object break _Jv_Find_class: java.lang.String break _Jv_Find_class: java.io.File Current language: auto; currently java break java.lang.VMClassLoader.getSystemClassLoader:300 break java.io.PrintStream.PrintStream(java.io.OutputStream, boolean) Current language: auto; currently c++ break _Jv_Find_class: gnu.gcj.convert.Output_UTF8 [New Thread 16385 (LWP 22563)] [New Thread 8194 (LWP 22564)] break _Jv_Find_class: java.lang.String break _Jv_Find_class: java.lang.Object break _Jv_Find_class: java.lang.String break _Jv_Find_class: java.lang.Object Program exited normally. (gdb) === trace with gcc HEAD 2004-01-15 13:08:06 UTC GNU gdb 6.0 Copyright 2003 Free Software Foundation, Inc. GDB is free software, covered by the GNU General Public License, and you are welcome to change it and/or distribute copies of it under certain conditions. Type "show copying" to see the conditions. There is absolutely no warranty for GDB. Type "show warranty" for details. This GDB was configured as "i686-pc-linux-gnu"... (gdb) (gdb) (gdb) (gdb) (gdb) (gdb) Breakpoint 1 at 0x804c3e0: file /berman/fsf/_today_/source/gcc/HEAD/gcc/libjava/prims.cc, line 895. (gdb) >>>>(gdb) (gdb) Breakpoint 2 at 0x8087161: file /berman/fsf/_today_/source/gcc/HEAD/gcc/libjava/java/lang/VMClassLoader.java, line 280. (gdb) >>>>(gdb) (gdb) Breakpoint 3 at 0x8087220: file /berman/fsf/_today_/source/gcc/HEAD/gcc/libjava/java/lang/VMClassLoader.java, line 300. (gdb) >>>>(gdb) (gdb) Breakpoint 4 at 0x808417e: file /berman/fsf/_today_/source/gcc/HEAD/gcc/libjava/java/lang/System.java, line 78. (gdb) >>>>(gdb) (gdb) Breakpoint 5 at 0x808c546: file /berman/fsf/_today_/source/gcc/HEAD/gcc/libjava/java/io/PrintStream.java, line 97. (gdb) >>>>(gdb) (gdb) Breakpoint 6 at 0x808c529: file /berman/fsf/_today_/source/gcc/HEAD/gcc/libjava/java/io/PrintStream.java, line 118. (gdb) >>>>(gdb) (gdb) Breakpoint 7 at 0x808c4dc: file /berman/fsf/_today_/source/gcc/HEAD/gcc/libjava/java/io/PrintStream.java, line 142. (gdb) >>>>(gdb) (gdb) Breakpoint 8 at 0x8071675: file /berman/fsf/_today_/source/gcc/HEAD/gcc/libjava/java/lang/natClassLoader.cc, line 481. (gdb) >>>>(gdb) (gdb) Starting program: /berman/home/mec.gnu/gcc/findclass/jmisc.today.exe [New Thread 8192 (LWP 32363)] [Switching to Thread 8192 (LWP 32363)] Current language: auto; currently c++ break _JvCreateJavaVM break _Jv_Find_class: java.lang.reflect.Field break _Jv_Find_class: java.security.Principal Current language: auto; currently java break java.lang.VMClassLoader.getSystemClassLoader break java.lang.System.<clinit>() Current language: auto; currently c++ break _Jv_Find_class: java.lang.Object Current language: auto; currently java break java.io.PrintStream.PrintStream(java.io.OutputStream, boolean) Current language: auto; currently c++ break _Jv_Find_class: gnu.gcj.convert.UnicodeToBytes break _Jv_Find_class: java.lang.Object break _Jv_Find_class: gnu.gcj.convert.Output_UTF8 Program received signal SIGSEGV, Segmentation fault. _Jv_FindClass(_Jv_Utf8Const*, java::lang::ClassLoader*) (name=0x0, loader=0x0) at /berman/fsf/_today_/source/gcc/HEAD/gcc/libjava/java/lang/natClassLoader.cc:507 507 klass = sys->loadClass (sname, false); (gdb) === findclass.gdbinit set height 0 set width 0 delete break _Jv_CreateJavaVM commands silent printf "break _JvCreateJavaVM\n" continue end break 'java.lang.VMClassLoader.getSystemClassLoader()' commands silent printf "break java.lang.VMClassLoader.getSystemClassLoader\n" continue end break VMClassLoader.java:300 commands silent printf "break java.lang.VMClassLoader.getSystemClassLoader:300\n" continue end break 'java.lang.System.<clinit>()' commands silent printf "break java.lang.System.<clinit>()\n" continue end break 'java.io.PrintStream.PrintStream(java.io.OutputStream)' commands silent printf "break java.io.PrintStream.PrintStream(java.io.OutputStream)\n" continue end break 'java.io.PrintStream.PrintStream(java.io.OutputStream, boolean)' commands silent printf "break java.io.PrintStream.PrintStream(java.io.OutputStream, boolean)\n" continue end break 'java.io.PrintStream.PrintStream(java.io.OutputStream, boolean, java.lang.String)' commands silent printf "break java.io.PrintStream.PrintStream(java.io.OutputStream, boolean, java.lang.String)\n" continue end break _Jv_FindClass commands silent printf "break _Jv_Find_class: %s\n", (const char *) name->data continue end run quit
2.14 shouldn't be too old to use...
Subject: Re: java program crashes at startup, UTF-8 environment Some more info: Did I mention that I configure my toolchains with --disable-shared? I bet that's why I encountered the bug and nobody else has. Try building gcc HEAD with "--disable-shared". Or just use a normal toolchain and build the Java executable with "-static". Both ways produce the segfault for me. It appears that the initialization procedure is different for shared libraries versus unshared archive libraries. Also, I date-searched the regression to this patch: 2004-01-14 Nathan Bryant <nbryant@optonline.net> Tom Tromey <tromey@redhat.com> PR libgcj/12001: * gnu/gcj/runtime/VMClassLoader.java (VMClassLoader): Pass empty array to superclass. (init): Changed interface; add URLs here. (initialize): New static method. * prims.cc (_Jv_CreateJavaVM): Initialize ClassLoader here... (_Jv_RunMain): ... not here. This matches the stack backtraces and the gdb traces that I saw: VMClassLoader.getSystemClassLoader calls System.getProperty class initialization for System constructs three standard PrintStream's. java.io.PrintStream.PrintStream calls Unicode stuff Unicode stuff wants to use a class loader Have a look at _Jv_FindClass. _Jv_FindClass calls _Jv_FindClassInCache, which returns a non-null klass if the class has been "loaded" or "initiated". With a shared library, I suspect that all the classes are getting "loaded" or "initiated" at the same time; with a static library, the class "gnu.gcj.convertOutput_UTF8" is definitely not "loaded" and not "initiated". I don't know the meanings of "loaded" and "initiated" so I can't say more than that. Anyways, link the program with "-static", and be sure to run with LANG=en_US.UTF-8, and you ought to see the segfault in _Jv_FindClass. Michael C
I think -static is not supported for gcj at all (or --disable-shared) because ld will not link against the needed objects. I cannot reproduce it with the mainline (3.5) with -static and 9.0 RedHat or a 7.3 RedHat box.
Subject: Re: [3.4/3.5 regression] java program crashes at startup, UTF-8 environment --disable-shared has been working fine for me with gcj 3.2, 3.2.1, 3.2.2, 3.2.3, 3.3, 3.3.1, 3.3.2, gcj gcc-3_3-branch, and gcj HEAD until last week. I've run my test bed with --disable-shared for two years and the Java test programs compile and link. --disable-shared is a documented feature. If -static and --disable-shared are not supported for java, can you write that in the documentation somewhere? Meanwhile, I'm really puzzled that I see this bug happening so easily, and you don't. I've put up my executables here: ftp://ftp.shout.net/pub/users/mec/java/jmisc.current.shared.exe ftp://ftp.shout.net/pub/users/mec/java/jmisc.current.static.exe ftp://ftp.shout.net/pub/users/mec/java/jmisc.java jmisc.current.static.exe exhibits the crash. jmisc.current.shared.exe does not crash. % LANG=en_US.UTF-8 jmisc.current.static.exe Can you put up your -static -gdwarf-2 executable somewhere, or directly mail it to me? I would like to figure out your executable DOESN'T crash. It should be about 10 megabytes long, which is why I didn't just attach it to the bug report. Michael C
Okay my static program is up on http://www.physics.uc.edu/~pinskia/jmisc.current.pinskia.exe. I could reproduce it with your excutable though but not when under gdb for some reason.
Subject: Re: [3.4/3.5 regression] java program crashes at startup, UTF-8 environment jmisc.current.pinskia.exe executes with no segfault on my system. I figured out the difference between jmisc.current.pinskia.exe and jmisc.current.static.exe. === Short version of the analysis: . _Jv_CreateJavaVM calls java.lang.ClassLoader.<clinit> . java.lang.ClassLoader.<clinit> calls java.lang.VMClassLoader.getSystemClassLoader . java.lang.VMClassLoader.getSystemClassLoader calls System.getProperty . java.lang.System.getProperty invokes java.lang.System.<clinit> . java.lang.System.<clinit> constructs some java.io.PrintStream objects . java.io.PrintStream.PrintStream calls gnu.gcj.convert.UnicodeToBytes.getDefaultEncoder . getDefaultEncoder loads a class whose name depends on the configuration options of libjava as well as the environment. . This class is "gnu.gcj.convert.Output_" + getProperty("file.encoding") . In jmisc.current.pinskia.exe: . getProperty("file.encoding") is "8859-1". . getDefaultEncoder tries to load "gnu.gcj.convert.Output_8859_1". . This class is already present in the static-linked executable. . Works fine. . In jmisc.current.static.exe: . getProperty("file.encoding") is "UTF-8". . getDefaultEncoder tries to load "gnu.gcj.convert.Output_UTF8". . This class is not already present in the static-linked executable. . So _Jv_FindClass uses the system class loader to go get it. . We are still in java.lang.ClassLoader.<clinit>, remember! . So the recursive call to ClassLoader.getSystemClassLoader returns NULL! . _Jv_FindClass segfaults on sys->loadClass because sys is NULL! Here is the difference between Andrew's executable and my executable. jmisc.current.pinskia.exe was built with a libgcj where the system property "file.encoding" is statically set to "8859-1". jmisc.current.static.exe was built with a libgcj where the system property "file.encoding" is dynamically initialized with a call to "setlocale", and my "file.encoding" is "UTF-8". This difference comes from a configuration check in natRuntime.cc for DEFAULT_FILE_ENCODING. From there, it turns out that gnu.gcj.convert.Output_8859_1 is statically linked into the program, but gnu.gcj.convert.Output_UTF8 is not. And the unicode code is running inside ClassLoader.<clinit>, so if it reaches for an output converter that is not already statically linked, then it dies. === Long version of the analysis: Start with this code in natRuntime.cc in gcc/libjava/java/lang/natRuntime.cc: #if ! defined (DEFAULT_FILE_ENCODING) && defined (HAVE_ICONV) \ && defined (HAVE_NL_LANGINFO) static char * file_encoding () { setlocale (LC_CTYPE, ""); char *e = nl_langinfo (CODESET); if (e == NULL || *e == '\0') e = "8859_1"; return e; } #define DEFAULT_FILE_ENCODING file_encoding () #endif #ifndef DEFAULT_FILE_ENCODING #define DEFAULT_FILE_ENCODING "8859_1" #endif static char *default_file_encoding = DEFAULT_FILE_ENCODING; In my executable, jmisc.current.static.exe, the "file_encoding" function is defined. There is a global ctor for "default_file_encoding". The global ctor runs at the right time and initializes "default_file_encoding" to the string "UTF-8". In your executable, jmisc.current.pinskia.exe, there is no "file_encoding" function. The string "default_file_encoding" is statically initialized to "8859_1". Note that this initialization depends on the values of HAVE_ICONV and HAVE_NL_LANGINFO when gcj was built. Next, java::lang::Runtime::insertSystemProperties does a simple: SET ("file.encoding", default_file_encoding); Later on, gnu.gcj.convert.UnicodeToBytes gets called. Breakpoint on that and do a stack trace. This is the killer stack trace! Here is the stack trace in both executables, jmisc.current.static.exe and jmisc.current.pinskia.exe. #0 gnu.gcj.convert.UnicodeToBytes.getDefaultEncoder #1 java.io.PrintStream.PrintStream #2 java.lang.System.<clinit> #3 java::lang::Class::initializeClass #4 java.lang.System.getProperty #5 java.lang.VMClassLoader.getSystemClassLoader #6 java.lang.ClassLoader.<clinit> #7 java::lang::Class::initializeClasss #8 _Jv_CreateJavaVM #9 _Jv_RunMain #10 JvRunMain #11 main See, the runtime is still initializing ClassLoader.<clinit>. ClassLoader.systemClassLoader is going to be NULL until this initialization is finished. ClassLoader.<clinit> has dragged in a bunch of other run-time initialization. getSystemClassLoader called get Property, which initializes System.<clinit>. System.<clinit> constructs the three standard streams (standard input, standard output, standard error). That invokes the Unicode encoder. UnicodeToBytes.getDefaultEncoder says: if (defaultEncoding == null) { String encoding = canonicalize (System.getProperty("file.encoding", "8859_1")); String className = "gnu.gcj.convert.Output_" + encoding; try { Class defaultEncodingClass = Class.forName(className); defaultEncoding = encoding; } In jmisc.current.pinskia.exe, the property "file.encoding" has the value "8859-1". className is "gnu.gcj.convert.Output_8859_1". In my executable, jmisc.current.static.exe, the property "file.encoding" has the value "UTF-8". className is "gnu.gcj.convert.Output_UTF8". Next, getDefaultEncoder calls Class.forName(className). This gets down to _Jv_FindClass. Look at _Jv_FindClass (in natClassLoader.cc): jclass _Jv_FindClass (_Jv_Utf8Const *name, java::lang::ClassLoader *loader) { jclass klass = _Jv_FindClassInCache (name, loader); if (! klass) { jstring sname = _Jv_NewStringUTF (name->data); java::lang::ClassLoader *sys = java::lang::ClassLoader::getSystemClassLoader (); if (loader) { ... } else { // Load using the bootstrap loader jvmspec 5.3.1. klass = sys->loadClass (sname, false); // Register that we're an initiating loader. if (klass) _Jv_RegisterInitiatingLoader (klass, 0); } If klass is in the cache, then _Jv_FindClass is happy and just returns. If klass is not in the cache, and loader is NULL (which it is), then this code attempts to use the system loader. But the system loader is NULL because we are still initializing it! See the stack trace above. That causes a segfault on "sys->loadClass (...)". So what determines whether a class is in the cache? _Jv_FindClassInCache has two hash tables, "loaded_classes" and "initiated_classes". If you break on _Jv_RegisterClassHookDefault, you can see this stack trace: _Jv_RegisterClassHookDefault _Jv_RegisterClasses frame_dummy completed.1 frame_dummy is in gcc/crtstuff.c. It calls _Jv_RegisterClasses on __JCR_LIST__ to register all the classes in __JCR_LIST__. This is simply the list of classes that are linked into the executable. I dumped all the classes in __JCR_LIST__ in jmisc.current.static.exe. There are 664 classes. The classes from gnu.gcj.convert are: gnu.gcj.convert.BytesToUnicode gnu.gcj.convert.Input_8859_1 gnu.gcj.convert.Input_iconv gnu.gcj.convert.IOConverter gnu.gcj.convert.UnicodeToBytes gnu.gcj.convert.Output_8859_1 gnu.gcj.convert.Output_iconv My executable does not have gnu.gcj.convert.Output_UTF8 linked in. So when getDefaultEncoder attempts to dynamically load it, it crashes, because getSystemClassLoader is still being initialized. Next, let me change the example program slightly: import gnu.gcj.convert.*; public class j2 { public static void main (String[] args) { Output_UTF8 foo = new gnu.gcj.convert.Output_UTF8 (); return; } } This program works! This code will work if any of these conditions are true: The executable is linked with a shared libgcj.so. I suspect that in a shared library, every class is in the __JCR_LIST__ for that library, whether it is used or not (how else could it work)? That is jmisc.current.shared.exe. The executable is built with a Java that was configured such that default_class_name is always "8859_1" instead of dynamically fetched from the locale. That is jmisc.current.pinskia.exe. The program contains an explicit reference to the output converter, such gnu.gcj.convert.Output_UTF8, or whatever the user will select at runtime via the locale environment variables. === How To Reproduce This Make sure that libgcj is built on a system where HAVE_ICONV and HAVE_NL_LANGINFO are true. Then build jmisc.exe with -static. Set $LANG to "en_US.UTF-8" and run the test program. It would be handy to change the test program to print the value of java.lang.System.getProperty("file.encoding"). === How To Fix This This needs some thought. ClassLoader.<clinit> wants to run very early. While this is running, it is restricted to classes that are linked into the program, either statically or shared. It can't class-load any classes. This is the cycle: ClassLoader.<clinit> calls VmClassLoader.getSystemClassLoader getSystemClassLoaders calls System.getProperty System.getProperty invokes System.<clinit> System.<clinit> constructs some new PrintStream's PrintStream.PrintStream drags in the unicode stuff unicode stuff needs the class loader We could break this cycle at any of those links. My first idea is to change VMClassLoader.getSystemClassLoader to use some low-level function rather than System.getProperty, so that it does not depend on all of System.<clinit>. That's a lot of code! My second idea is to re-organize System so that System.<clinit> is more light weight and safe to invoke before the class loader has been initialized. Another idea is to change UnicodeToBytes.getDefaultEncoder so that it uses if/else logic rather than calling Class.forName. getDefaultEncoder is invoked during class loader initialization, so it has to to work without using the class loader: String encoding = canonicalize (System.getProperty("file.encoding", "8859_1")); if (encoding == "8859_1" ) { return new Output_8859_1 (); } else if (encoding == "ASCII" ) { return new Output_ASCII (); } else if (encoding == "EUCJIS" ) { return new Output_EUCJIS (); } else if (encoding == "JavaSrc" ) { return new Output_JavaSrc (); } else if (encoding == "SJIS" ) { return new Output_SJIS (); } else if (encoding == "UTF8" ) { return new Output_UTF8 (); } else if (encoding == "iconv" ) { return new Output_iconv (); } else { throw new NoClassDefFoundError ( "missing default encoding " + encoding " + " (class " + className + "not found)"; } Yeah, it's ugly. From my perspective, the ugly part is that so much code is invoked before the class loader is initialized. Alternatively, you could declare that "-static" does not work with libgcj, and libgcj must be a shared library. It would be nice to have a better diagnostic than a core dump. Specifically, if native C++ code is about to use a NULL system class loader, than throw a diagnostic rather than dereferencing a NULL pointer.
Java problems are not showstoppers so I have moded the target milestone to 3.4.1.
Patch here: <http://gcc.gnu.org/ml/gcc-patches/2004-01/msg03355.html>.
*** Bug 14636 has been marked as a duplicate of this bug. ***
*** Bug 12908 has been marked as a duplicate of this bug. ***
Tom -- I'm postponing this PR yet again, but this problem is an embarassment. It's been reported several times and it makes gcj completely unusable for affected users. Any chance you could review the patch attached to the PR? -- Mark
Mark, I looked at this. This is a longstanding gcj issue. I hesitate to call it a problem because, as I see it, static linking with gcj can't really be made completely robust. The user will always need to know something about his application and will have to explicitly link in classes that are only discovered via reflection. This is a general issue affecting not just libgcj itself but any java library one might link against. I looked at the patch in question. It is reasonable enough, though it still needs a tweak (there is no encoding named "iconv", that handler is a special case). I'd prefer not to check it in. I think that, if it is fixed, real programs will just run into further problems down the road. For instance, a statically linked program won't have any locales compiled in. This means that java.text.* will work mysteriously, or perhaps fail, depending on the circumstances. Likewise for java.util.Calendar. The fix we ordinarily recommend is to have your program directly reference the encoders and locales it plans to use. This is not very satisfactory, I realize, but static linking isn't fully supported.
Subject: Re: [3.4/3.5 regression] static java program crashes at startup, UTF-8 environment Okay, if static linking with gcj can't be made robust, then how about we (1) change the documentation to say that it isn't supported, and (2) change the code to do something more informative than the current behavior, which is a null-pointer-dereference on startup? Michael C
>Mark, I looked at this. > >This is a longstanding gcj issue. I hesitate to call it >a problem because, as I see it, static linking with gcj >can't really be made completely robust. My 2 cents. - Static linking is one of the unique features of GCJ - libgcj.dll doesn't exist yet under Windows Øyvind
This is not a regression at really, the problem comes from the fact that linker removes the object files which are not referenced in which means that the Java classes are removed when they should not be.
Subject: Re: static java program crashes at startup, UTF-8 environment I consider this a regression because the test program works with gcc 3.3.3 and does not work with gcc 3.4.0 and gcc HEAD. However, if you don't consider it a regression, okay. Michael C
*** Bug 16899 has been marked as a duplicate of this bug. ***
For those of us who use gcj in the embedded arena, having static support is crucial. Many embedded projects can't use a real JVM for performance or memory footprint reasons. Making statically-linked executables is ideal for porting Java code into embedded devices.
*** Bug 18459 has been marked as a duplicate of this bug. ***
*** Bug 21793 has been marked as a duplicate of this bug. ***
(In reply to comment #29) > *** Bug 21793 has been marked as a duplicate of this bug. *** The same example works with the MinGW version of gcj-3.4.2? And it works when I set the encoding to ISO-8859-1: $ /usr/bin/gcj -Dfile.encoding=ISO-8859-1 --main=hello_j hello_j.java -o hello_j $ ./hello_j Just another Java hacker, How do I set the default encoding to ISO-8859-1 when building gcj? And when will GCC be switched to use >= libtool-1.5.10 and newer automake & autoconf versions? Shared libraries are not supported by the antiquated libtool and friends used by GCC. Gerrit
Static linking can never work correctly with libjava/libgcj/gcj.
*** Bug 22094 has been marked as a duplicate of this bug. ***
*** Bug 21068 has been marked as a duplicate of this bug. ***