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

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]);
  }
}
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]);
  }
}

Reply via email to