bug in the ClassLoader

Tony Knaus awk@spinnakernet.com
Sun Aug 26 13:25:00 GMT 2001


Hi,
	While trying to build Apache Tomcat I have stumbled 
across a condition where the buckets in the hash table implementing 
the class cache in java/lang/natClassLoader.cc become populated with 
cycles in the linked list. This causes the jvm to intermittently 
hang when the class loader tries to find a class in the cache which 
hashes to a bucket that has a cycle in it. 
	This bug occured when I built a separate shared 
library with java security objects from the gnu classpath 
to supply missing definitions to Tomcat I inadvertently
had a some duplication of the class name space between the 
two libraries. Each one of the duplicated objects causes
a linked list pointer cycle in the class cache hash table.
Removing the duplication fixes the class cache.
Also the cycles only seems to occur when there is a 
name collision between the name of an object in a shared 
library and gcj libjava. My attempts to duplicate it using 
arbitrarily choosen class names and libraries have failed.
Attached are instructions for duplicating this bug and 
a gdb session displaying it. 
-tony
To repeat class loader bug
1) Add the folloing debug stub to libjava/java/lang/natClassLoader.cc
void PrintClassPathStats() 
{
 _Jv_MonitorEnter (&ClassClass);
 jclass klass;
 int nfound=0;
 for(int i=0; i<HASH_LEN; i++) {
 for (klass = loaded_classes[i]; klass; klass = klass->next) {
 nfound++;
 fprintf(stderr," hash bucket: %d class %d name ", i, nfound);
 for(int j=0; j<klass->name->length; j++) {
 fprintf(stderr, "%c", (char) (klass->name->data[j]));
 }
 fprintf(stderr," klass=%p next=%p\n", klass, klass->next);
 fflush(stderr);
 if (klass == klass->next) break;
 }
 }
 fprintf(stderr,"number of classes found: %d\n", nfound);
 _Jv_MonitorExit (&ClassClass);
}
2) Make PrintClassPathStats a friend of jclass by adding
 friend void PrintClassPathStats();
 to libjava/java/lang/Class.h
3) recompile libjava
4) Using any one of the objects defined in libjava
 and compile and link into a separate library shared
 library. In this example I used java/security/DigestException.java
 from the gnu classpath.
% /usr/local/gcc-3.0/bin/gcj -g --encoding=UTF-8 -shared -o libtest.so java/security/DigestException.o
5) Compile the following program and run gdb.
import java.util.ResourceBundle;
import java.security.DigestException;
public class TestClassLoader {
 public static void main(String[] args) {
 try {
 } catch(DigestException e) {};
 ResourceBundle b = ResourceBundle.getBundle("foo");
 }
}
% /usr/local/gcc-3.0/bin/gcj -g --encoding=UTF-8 -CLASSPATH "." TestClassLoader.java -o TestClassLoader --main=TestClassLoader ./libtest.so -Wl,--rpath -Wl,/usr/local/gcc-3.0/lib -Wl,--rpath -Wl,/usr/local/gcc-3.0/lib/gcc-lib/i686-pc-linux-gnu/3.0.1
------------------------ gdb trace --------------------------------
> /usr/bin/gdb TestClassLoader
GNU gdb 19991004
Copyright 1998 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 "i386-redhat-linux"...
(gdb) l 'TestClassLoader' 
1	import java.util.ResourceBundle;
2	import java.security.DigestException;
3	
4	public class TestClassLoader {
5	 public static void main(String[] args) {
6		try {
7		} catch(DigestException e) {};
8	
9		ResourceBundle b = ResourceBundle.getBundle("foo");
10	 }
(gdb) b 9
Breakpoint 1 at 0x8048ea6: file TestClassLoader.java, line 9.
(gdb) run
Starting program: /home/awk/test_case/TestClassLoader 
[New Thread 3403 (manager thread)]
[New Thread 3402 (initial thread)]
[New Thread 3404]
[Switching to Thread 3404]
Breakpoint 1, _ZN15TestClassLoader4mainEP6JArrayIPN4java4lang6StringEE (args=null) at TestClassLoader.java:9
9		ResourceBundle b = ResourceBundle.getBundle("foo");
Current language: auto; currently java
(gdb) l _Z19PrintClassPathStatsv
<skip to FindClassInCache>
(gdb) l
355	
356	^L
357	
358	jclass
359	_Jv_FindClassInCache (_Jv_Utf8Const *name, java::lang::ClassLoader *loader)
360	{
361	 _Jv_MonitorEnter (&ClassClass);
362	 jint hash = HASH_UTF (name);
363	
364	 // first, if LOADER is a defining loader, then it is also initiating
(gdb) l
365	 jclass klass;
366	 for (klass = loaded_classes[hash]; klass; klass = klass->next)
367	 {
368	 if (loader == klass->loader && _Jv_equalUtf8Consts (name, klass->name))
369		break;
370	 if (klass == klass->next) {
371			
372		fprintf(stderr,"error loop in class loader klass=%p next=%p\n", klass, klass->next);
373		klass->next=0;
374	 }
(gdb) b 368
Breakpoint 2 at 0x40177068: file ../../../gcc/libjava/java/lang/natClassLoader.cc, line 368.
(gdb) c
Continuing.
Breakpoint 2, _Z20_Jv_FindClassInCacheP13_Jv_Utf8ConstPN4java4lang11ClassLoaderE (name=0x8084f90, loader=0x0)
 at ../../../gcc/libjava/java/lang/natClassLoader.cc:368
368	 if (loader == klass->loader && _Jv_equalUtf8Consts (name, klass->name))
Current language: auto; currently c++
(gdb) call _Z19PrintClassPathStatsv()
 hash bucket: 0 class 1 name java.security.DigestException klass=0x40015280 next=0x4033b6e0
 hash bucket: 0 class 2 name java.net.ServerSocket klass=0x4033b6e0 next=0x40015280
 hash bucket: 0 class 3 name java.security.DigestException klass=0x40015280 next=0x4033b6e0
 hash bucket: 0 class 4 name java.net.ServerSocket klass=0x4033b6e0 next=0x40015280
 hash bucket: 0 class 5 name java.security.DigestException klass=0x40015280 next=0x4033b6e0
 hash bucket: 0 class 6 name java.net.ServerSocket klass=0x4033b6e0 next=0x40015280
 hash bucket: 0 class 7 name java.security.DigestException klass=0x40015280 next=0x4033b6e0
 hash bucket: 0 class 8 name java.net.ServerSocket klass=0x4033b6e0 next=0x40015280
 hash bucket: 0 class 9 name java.security.DigestException klass=0x40015280 next=0x4033b6e0
 hash bucket: 0 class 10 name java.net.ServerSocket klass=0x4033b6e0 next=0x40015280
 [Switching to Thread 3402 (initial thread)]
Program received signal SIGINT, Interrupt.
0x4051a58b in __sigsuspend (set=0xbffff9e4) at ../sysdeps/unix/sysv/linux/sigsuspend.c:48
48	../sysdeps/unix/sysv/linux/sigsuspend.c: No such file or directory.
The program being debugged stopped while in a function called from GDB.
When the function (_Z19PrintClassPathStatsv) is done executing, GDB will silently
stop (instead of continuing to evaluate the expression containing
the function call).
(gdb) quit
The program is running. Exit anyway? (y or n) y
Script done on Sun Aug 26 14:56:58 2001
 


More information about the Java mailing list

AltStyle によって変換されたページ (->オリジナル) /