[kaffe] Classloader bugs
Daniel Bonniot
Daniel.Bonniot@inria.fr
Mon Nov 17 20:03:01 2003
This is a multi-part message in MIME format.
--------------050707090507080704040109
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit
Hi,
I think I am experimenting two Classloader bugs, in Kaffe CVS (built a
few minutes ago). The good thing is that I have pretty small testcases.
Bug.java simply exercises loading from a URLClassLoader. The catch is
that it is fragile on the presence or absence of a '/' at the end of the
URL, for a file URL (this might also be a bug in java.net.URL, I am not
sure).
(all this is on a Linux host)
$ javac Bug.java
$ java Bug $PWD Bug
$ kaffe Bug $PWD Bug
java.lang.ClassNotFoundException: Bug not found in
[file:/home/daniel/tmp/kaffe-bug]
at java.net.URLClassLoader.findClass (URLClassLoader.java:769)
at java.lang.ClassLoader.loadClass (ClassLoader.java:142)
at java.lang.ClassLoader.loadClass (ClassLoader.java:121)
at Bug.main (Bug.java:9)
$ echo $PWD
/home/daniel/tmp/kaffe-bug
$ kaffe Bug $PWD/ Bug
$
Note how adding '/' at the end of the URL makes the classloader find the
class.
The second bug is only slightly more complex. It involves a custom class
loader. I have no interpretation of this bug at the moment, looks like
an internal error.
$ javac Bug2.java
$ java Bug2 $PWD/ Bug2
$ kaffe Bug2 $PWD/ Bug2
java.lang.NullPointerException
at java.lang.ClassLoader.defineClass0 (ClassLoader.java)
at java.lang.ClassLoader.defineClass (ClassLoader.java:179)
at java.security.SecureClassLoader.defineClass
(SecureClassLoader.java:33)
at java.net.URLClassLoader.findClass (URLClassLoader.java:855)
at Bug2$1.loadClass (Bug2.java:23)
at java.lang.ClassLoader.loadClass (ClassLoader.java:121)
at Bug2.main (Bug2.java:36)
It's also interesting to see what happens when trying to load a class
that does not exist:
$ java Bug2 $PWD/ Foo
Exception in thread "main" java.lang.ClassNotFoundException: Foo
at java.net.URLClassLoader$1.run(URLClassLoader.java:198)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:186)
at java.lang.ClassLoader.loadClass(ClassLoader.java:299)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:265)
at java.lang.ClassLoader.loadClass(ClassLoader.java:255)
at Bug2$1.loadClass(Bug2.java:28)
at java.lang.ClassLoader.loadClass(ClassLoader.java:255)
at Bug2.main(Bug2.java:36)
$ kaffe Bug2 $PWD/ Foo
java.lang.NullPointerException
at Bug2$1.loadClass (Bug2.java:28)
at java.lang.ClassLoader.loadClass (ClassLoader.java:121)
at Bug2.main (Bug2.java:36)
I just checked the javadoc of java.lang.ClassLoader.getParent. It
explicitely says that some implementations might return null to
represent the bootstrap class loader. So the behaviour of kaffe in the
second case (while searching for Foo) is not incorrect. It might still
explain the bug in the first case (searching for Bug2) -- or not, since
the lookup should succeed in the current classloader, not its parent. In
any case, it sounds like a better idea to me to return the bootstrap
class loader than to return null.
Cheers,
Daniel
--------------050707090507080704040109
Content-Type: text/x-java;
name="Bug.java"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
filename="Bug.java"
public class Bug
{
public static void main(String[] args)
throws java.net.MalformedURLException, ClassNotFoundException
{
String url = "file://" + args[0];
ClassLoader loader = new java.net.URLClassLoader
(new java.net.URL[]{ new java.net.URL(url) });
loader.loadClass(args[1]);
}
}
--------------050707090507080704040109
Content-Type: text/x-java;
name="Bug2.java"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
filename="Bug2.java"
public class Bug2
{
public static void main(String[] args)
throws java.net.MalformedURLException, ClassNotFoundException
{
String url = "file://" + args[0];
ClassLoader loader = new java.net.URLClassLoader
(new java.net.URL[]{ new java.net.URL(url) })
{
protected Class loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
/* Change the default behviour, which is to look up the
parent classloader first. Instead, look it up after this one,
so that the inlined methods are found here, but the
interfaces they implement are found in the system classloader,
so that the casts for using them succeed.
*/
Class res = findLoadedClass(name);
if (res == null)
try {
res = this.findClass(name);
}
catch (ClassNotFoundException ex) {}
if (res == null)
res = getParent().loadClass(name);
if (resolve && res != null)
resolveClass(res);
return res;
}
};
loader.loadClass(args[1]);
}
}
--------------050707090507080704040109--