From: huw@dcs.gla.ac.uk
Date: Mon, 3 Nov 1997 19:25:20 GMT
Message-Id: <199711031925.TAA13231@hawaii.dcs.gla.ac.uk>
To: java-security@web2.javasoft.com
Subject: ClassLoader bug
Although not directly related to security, as it is to do with
the ClassLoader, I thought the experts in security would be able
to shed some light on it.
Please forward this if this mailing list is not relevant.
Platform: Solaris Sparc version of jdk
Platform Version: jdk 1.1.4
Error in: java.lang.ClassLoader
One Line Description
--------------------
Implementation of ClassLoader fails to load class/class cast exception
is seen
Detailed Explanation
--------------------
This error is preventing me from continuting
with my work. Example code is included below.
There are three files below. Save each to the
relevant file. You should then have
TestClassLoader.java, Test.java and A.java
% javac *.java
% export CLASSPATH=.
% java Test
In loadClass(String typename, boolean resolve)
Looking for class: A
Before defineClass
In loadClass(String typename, boolean resolve)
Aftere defineClass
c: class A
java.lang.ClassCastException: A
at Test.main(Test.java:21)
Why does this ClassCastException occur?
In TestClassLoader.java is a comment
that mentions SYSTEM CODE CHECK. If
this comment is changed so that the
isSystemCode method is never called, ie:
/* SYSTEM CODE CHECK
if(isSystemCode(typename))
return findSystemClass(typename);
END OF SYSTEM CODE CHECK */
and I recompile and rerun:
% javac *.java
% java Test
I get a different error:
% java Test
In loadClass(String typename, boolean resolve)
Looking for class: A
Before defineClass
In loadClass(String typename, boolean resolve)
Looking for class: java.lang.Object
Before defineClass
java.lang.NoClassDefFoundError
The use of the isSystemCode method was
a naff attempt to solve the problem. Only
it doesn't work. I need to be able to load
a .class file from disk and get at the bytes
as I am sending the bytes across the network
and at the remote site executing defineClass.
In my distributed version I see the
java.lang.NoClassDefFoundError.
I thought it may be because java.lang.Object
is being loaded and the VM was getting confused
about which version of java.lang.Object it
had loaded as java.lang.Object must have
already been loaded by the default class
loader by the time the code gets
to the main(String argv[]) method.
Any help would be much appreciated.
This is preventing me from continuting with my
work.
// Start of TestClassLoader.java
import java.io.*;
import java.util.Hashtable;
public class TestClassLoader extends ClassLoader
{
Hashtable cache;
public TestClassLoader()
{
this.cache = new Hashtable();
}
private String translateTypenameToPathFormat(String typename)
{
return typename.replace('.', '/') + ".class";
}
private boolean isSystemCode(String typename)
{
return typename.startsWith("java.") || typename.startsWith("sun.");
}
public Class loadClass(String typename, boolean resolve) throws ClassNotFoundException
{
System.out.println("In loadClass(String typename, boolean resolve)");
/* SYSTEM CODE CHECK */
if(isSystemCode(typename))
return findSystemClass(typename);
/* END OF SYSTEM CODE CHECK */
if(inCache(typename))
return getCacheEntry(typename);
InputStream in = ClassLoader.getSystemResourceAsStream(translateTypenameToPathFormat(typename));
if(in == null)
throw new ClassNotFoundException("Cannot get system resource as stream from typename: " + typename);
int available = 0;
try {
available = in.available();
} catch(java.io.IOException ioe) {
ioe.printStackTrace();
System.exit(2);
}
System.out.println("Looking for class: " + typename);
byte[] b = new byte[available];
try {
in.read(b);
} catch(java.io.IOException ioe) {
ioe.printStackTrace();
System.exit(3);
}
Class c = null;
try {
System.out.println("Before defineClass");
c = defineClass(typename, b, 0, b.length);
System.out.println("Aftere defineClass");
} catch(Exception e) {
e.printStackTrace();
System.exit(5);
} catch(java.lang.ClassFormatError cfe) {
cfe.printStackTrace();
System.exit(6);
}
System.out.println("c: " + c);
if(resolve)
resolveClass(c);
updateCache(typename, c);
return c;
}
public Class loadClass(String typename) throws ClassNotFoundException
{
System.out.println("In loadClass(String typename)");
if(inCache(typename))
return getCacheEntry(typename);
return loadClass(typename, true);
}
private void updateCache(String typename, Class c)
{
cache.put(typename, c);
}
private boolean inCache(String typename)
{
return cache.containsKey(typename);
}
private Class getCacheEntry(String typename)
{
System.out.println(typename + " in cache. Using cached version");
return (Class) cache.get(typename);
}
}
// END OF TestClassLoader.java
// Start of Test.java
public class Test
{
public static void main(String argv[])
{
TestClassLoader tcl = new TestClassLoader();
Class classA = null;
try {
classA = tcl.loadClass("A", true);
} catch(java.lang.ClassNotFoundException cnfe) {
cnfe.printStackTrace();
System.exit(1);
}
A a = null;
try {
a = (A) classA.newInstance();
} catch(java.lang.Exception e) {
e.printStackTrace();
System.exit(2);
}
}
}
// End of Test.java
// Start of A.java
public class A
{
}
// End of A.java
Workd Around
------------
I do not know of one. They one I attempted,
isSystemCode, didn't work, and another error
was generated.
This is preventing me from continuting with my
work.