From mboxrd@z Thu Jan 1 00:00:00 1970 From: osk@hem.passagen.se To: java-gnats@sourceware.cygnus.com Subject: java/1365: deadlock in _Jv_FindClassInCache Date: Wed, 20 Dec 2000 12:25:00 -0000 Message-id: <20000904155011.25468.qmail@sourceware.cygnus.com> X-SW-Source: 2000-q4/msg01141.html List-Id: >Number: 1365 >Category: java >Synopsis: deadlock in _Jv_FindClassInCache >Confidential: no >Severity: serious >Priority: medium >Responsible: apbianco >State: analyzed >Class: sw-bug >Submitter-Id: net >Arrival-Date: Wed Dec 20 12:19:18 PST 2000 >Closed-Date: >Last-Modified: Sun Sep 10 17:40:00 PDT 2000 >Originator: Oskar Liljeblad >Release: unknown-1.0 >Organization: >Environment: >Description: The program below gets in a deadloop when it is started. This is probably because java.util.AbstractList is initialized in the libgcj "main" before the class main is actually run. (I guess AbstractList is used by some System class or something.) As AbstractList is overriden by the dummy-class below, havoc breaks loose. I'm not sure this is a bug, but it would be nice if some appropriate exception was thrown instead of a deadlock occuring... Oskar Liljeblad (osk@hem.passagen.se) >How-To-Repeat: mkdir -p java/util echo >java/util/AbstractList.java <<__END__ package java.util; abstract class AbstractList { static class SubList extends AbstractList { public SubList(AbstractList backing) { } } } __END__ echo >test.java <<__END__ class test { public static void main(String[] args) { } } __END__ gcj -o test --main=test *.java java/util/*.java ./test >Fix: The deadloop occurs in _Jv_FindClassInCache in libjava/java/lang/natClassLoader.cc near line 345. klass and klass->next is the same when klass->name is something like "java.util.AbstractList$SubList". >Release-Note: >Audit-Trail: Formerly PR gcj/338 State-Changed-From-To: open->analyzed State-Changed-By: green State-Changed-When: Sun Sep 10 12:57:49 2000 State-Changed-Why: What's happening here is that we have a class living in both a shared library and the main program. The AbstractList class is registered when the main program starts up. This is done through the use of the per-class static constructors. The same thing happens when the libgcj shared library is loaded. When the same class is registered twice we end up with a loop in the class cache (klass->next == klass). Here's one way to avoid the deadloop symptom. It's difficult to say what the right thing to do is. Index: java/lang/natClassLoader.cc =================================================================== RCS file: /cvs/java/libgcj/libjava/java/lang/natClassLoader.cc,v retrieving revision 1.25 diff -u -r1.25 natClassLoader.cc --- natClassLoader.cc 2000/07/20 19:31:16 1.25 +++ natClassLoader.cc 2000/09/10 19:51:49 @@ -436,7 +436,18 @@ for (; *classes; ++classes) { jclass klass = *classes; - jint hash = HASH_UTF (klass->name); + _Jv_Utf8Const *name = klass->name; + jint hash = HASH_UTF (name); + // In certain situations we may find ourselves registering the + // same class twice (but with different implementations). For + // instance, foo.Bar may exist in two different shared + // libraries. The first class registered wins in this case, and + // we proceed silently. + for (jclass k = loaded_classes[hash]; k; k = k->next) + { + if (_Jv_equalUtf8Consts (name, k->name)) + return; + } klass->next = loaded_classes[hash]; loaded_classes[hash] = klass; From: green@cygnus.com To: apbianco@cygnus.com, java-gnats@sourceware.cygnus.com, osk@hem.passagen.se Cc: Subject: Re: gcj/338 Date: 10 Sep 2000 19:57:49 -0000 Synopsis: deadlock in _Jv_FindClassInCache State-Changed-From-To: open->analyzed State-Changed-By: green State-Changed-When: Sun Sep 10 12:57:49 2000 State-Changed-Why: What's happening here is that we have a class living in both a shared library and the main program. The AbstractList class is registered when the main program starts up. This is done through the use of the per-class static constructors. The same thing happens when the libgcj shared library is loaded. When the same class is registered twice we end up with a loop in the class cache (klass->next == klass). Here's one way to avoid the deadloop symptom. It's difficult to say what the right thing to do is. Index: java/lang/natClassLoader.cc =================================================================== RCS file: /cvs/java/libgcj/libjava/java/lang/natClassLoader.cc,v retrieving revision 1.25 diff -u -r1.25 natClassLoader.cc --- natClassLoader.cc 2000/07/20 19:31:16 1.25 +++ natClassLoader.cc 2000/09/10 19:51:49 @@ -436,7 +436,18 @@ for (; *classes; ++classes) { jclass klass = *classes; - jint hash = HASH_UTF (klass->name); + _Jv_Utf8Const *name = klass->name; + jint hash = HASH_UTF (name); + // In certain situations we may find ourselves registering the + // same class twice (but with different implementations). For + // instance, foo.Bar may exist in two different shared + // libraries. The first class registered wins in this case, and + // we proceed silently. + for (jclass k = loaded_classes[hash]; k; k = k->next) + { + if (_Jv_equalUtf8Consts (name, k->name)) + return; + } klass->next = loaded_classes[hash]; loaded_classes[hash] = klass; http://sources.redhat.com/cgi-bin/gnatsweb.pl?cmd=view&pr=338&database=java From: Tom Tromey To: green@cygnus.com Cc: apbianco@cygnus.com, java-gnats@sourceware.cygnus.com Subject: Re: gcj/338 Date: 10 Sep 2000 17:31:12 -0600 Anthony> Here's one way to avoid the deadloop symptom. It's difficult Anthony> to say what the right thing to do is. One idea would be to throw a LinkageError because the class is already loaded. See ClassLoader.defineclass. Comments on this idea? Tom From: Anthony Green To: "'tromey@cygnus.com'" Cc: "apbianco@cygnus.com" , "java-gnats@sourceware.cygnus.com" Subject: RE: gcj/338 Date: Sun, 10 Sep 2000 17:33:23 -0700 On Sunday, September 10, 2000 4:31 PM, Tom Tromey [SMTP:tromey@cygnus.com] wrote: > One idea would be to throw a LinkageError because the class is already > loaded. See ClassLoader.defineclass. > > Comments on this idea? Can we do this reliably at static constructor initialization time? AG >Unformatted: