Hi,

While digging around the class loading issues, I discovered that we
didn't record a class with the "initiating loader" [1]. This is
necessary to maintain type safety in the face of buggy or malicious
class loaders (or even when the contents of the directories in the
classpath change).

I've also attached a Mauve test case that checks for everything I could
think of. These tests pass on IBM JDK 1.3, Sun JDK 1.4, Sun JDK 1.5 and
my local IKVM version.

Please comment.

Regards,
Jeroen

[1]
http://java.sun.com/j2se/1.5.0/docs/api/java/lang/ClassLoader.html#findL
oadedClass(java.lang.String)

2005-07-27  Jeroen Frijters  <[EMAIL PROTECTED]>

        * java/lang/Class.java
        (forName(String), forName(String,boolean,ClassLoader)): Added
call to
        VMClassLoader.registerInitiatingLoader.
        * java/lang/ClassLoader.java
        (defineClass(String,byte[],int,int,ProtectionDomain):
        Changed to call VMClassLoader.registerInitiatingLoader.
        * vm/reference/java/lang/VMClassLoader.java
        (findLoadedClass): Added synchronization.
        (registerInitiatingLoader): New method.
Index: java/lang/Class.java
===================================================================
RCS file: /cvsroot/classpath/classpath/java/lang/Class.java,v
retrieving revision 1.37
diff -u -r1.37 Class.java
--- java/lang/Class.java        2 Jul 2005 20:32:38 -0000       1.37
+++ java/lang/Class.java        27 Jul 2005 11:13:13 -0000
@@ -156,11 +156,16 @@
    */
   public static Class forName(String name) throws ClassNotFoundException
   {
-    Class result = VMClass.forName (name);
-    if (result == null)
-      result = Class.forName(name, true,
-       VMStackWalker.getCallingClassLoader());
-    return result;
+    ClassLoader cl = VMStackWalker.getCallingClassLoader();
+    Class result = VMClass.forName(name);
+    if (result != null)
+      {
+        if (cl != null)
+          VMClassLoader.registerInitiatingLoader(cl, result);
+        return result;
+      }
+    else
+      return forName(name, true, cl);
   }
 
   /**
@@ -216,13 +221,27 @@
          }
         throw new ClassNotFoundException(name);
       }
-    if (name.startsWith("["))
-      return VMClass.loadArrayClass(name, classloader);
-    Class c = classloader.loadClass(name);
-    classloader.resolveClass(c);
-    if (initialize)
-      VMClass.initialize(c);
-    return c;
+    else
+      {
+        // Take a shortcut, if possible. This is not just a performance
+        // tweak, but it also helps protect us from broken class loaders.
+        Class c = classloader.findLoadedClass(name);
+        if (c == null)
+          {
+            if (name.startsWith("["))
+              {
+                c = VMClass.loadArrayClass(name, classloader);
+                VMClassLoader.registerInitiatingLoader(classloader, c);
+                return c;
+              }
+            c = classloader.loadClass(name);
+            VMClassLoader.registerInitiatingLoader(classloader, c);
+          }
+        classloader.resolveClass(c);
+        if (initialize)
+          VMClass.initialize(c);
+        return c;
+      }
   }
   
   /**
Index: java/lang/ClassLoader.java
===================================================================
RCS file: /cvsroot/classpath/classpath/java/lang/ClassLoader.java,v
retrieving revision 1.54
diff -u -r1.54 ClassLoader.java
--- java/lang/ClassLoader.java  25 Jul 2005 14:28:42 -0000      1.54
+++ java/lang/ClassLoader.java  27 Jul 2005 11:13:14 -0000
@@ -480,7 +480,7 @@
     Class retval = VMClassLoader.defineClass(this, name, data,
                                             offset, len, domain);
     if (! VMClassLoader.USE_VM_CACHE)
-      loadedClasses.put(retval.getName(), retval);
+      VMClassLoader.registerInitiatingLoader(this, retval);
     return retval;
   }
 
Index: vm/reference/java/lang/VMClassLoader.java
===================================================================
RCS file: 
/cvsroot/classpath/classpath/vm/reference/java/lang/VMClassLoader.java,v
retrieving revision 1.29
diff -u -r1.29 VMClassLoader.java
--- vm/reference/java/lang/VMClassLoader.java   26 Jul 2005 06:46:20 -0000      
1.29
+++ vm/reference/java/lang/VMClassLoader.java   27 Jul 2005 11:13:19 -0000
@@ -292,9 +292,52 @@
 
   /**
    * If the VM wants to keep its own cache, this method can be replaced.
+   * If the name represents an array type, the ultimate component type
+   * is looked up and the array type is created.
    */
   static Class findLoadedClass(ClassLoader cl, String name)
   {
-    return (Class) cl.loadedClasses.get(name);
+    synchronized (cl.loadedClasses)
+      {
+        return (Class) cl.loadedClasses.get(name);
+      }
+  }
+
+  /**
+   * This method is called by Class.forName() to notify the VM that a
+   * particular class loader should be recorded as the initiating loader for
+   * a class. Note that ClassLoader.findLoadedClass() should see classes that
+   * have been registered through this method.
+   * When the VM internally loads a class, it should call this method
+   * to record the class with the initiating class loader.
+   * Note that when an array type is registered, the ultimate component type
+   * is registered instead.
+   *
+   * @param cl Class loader instance (should not be null)
+   * @param c Class to be associated with this class loader
+   * @throws LinkageError if a different class with the same name was
+   * already loaded by this class loader.
+   */
+  static void registerInitiatingLoader(ClassLoader cl, Class c)
+    throws LinkageError
+  {
+    synchronized (cl.loadedClasses)
+      {
+        Object prev = cl.loadedClasses.get(c.getName());
+        if (prev != c)
+          {
+            if (prev != null)
+              throw new LinkageError("Duplicate class definition: "
+                                     + c.getName());
+            if (c.isArray())
+              {
+                Class componentType = c.getComponentType();
+                while (componentType.isArray())
+                  componentType = componentType.getComponentType();
+                registerInitiatingLoader(cl, componentType);
+              }
+            cl.loadedClasses.put(c.getName(), c);
+          }
+      }
   }
 }

Attachment: findLoadedClass.java
Description: findLoadedClass.java

_______________________________________________
Classpath-patches mailing list
[email protected]
http://lists.gnu.org/mailman/listinfo/classpath-patches

Reply via email to