[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--