6832540: IllegalArgumentException in ClassLoader.definePackage when classes are loaded in parallel
authorvaleriep
Mon, 13 Jul 2009 15:14:17 -0700
changeset 3228 d7c00dbea781
parent 3227 a3484e08f2bc
child 3229 6fc2e89be40c
child 3311 a219a6c036a6
child 3470 a48a6dab9eb6
6832540: IllegalArgumentException in ClassLoader.definePackage when classes are loaded in parallel Summary: Modified to handle race condition for parallel-capable classloaders by re-trying/re-verifying package Reviewed-by: alanb
jdk/src/share/classes/java/net/URLClassLoader.java
--- a/jdk/src/share/classes/java/net/URLClassLoader.java	Mon Jul 13 23:01:03 2009 +0800
+++ b/jdk/src/share/classes/java/net/URLClassLoader.java	Mon Jul 13 15:14:17 2009 -0700
@@ -306,6 +306,35 @@
     }
 
     /*
+     * Retrieve the package using the specified package name.
+     * If non-null, verify the package using the specified code
+     * source and manifest.
+     */
+    private Package getAndVerifyPackage(String pkgname,
+                                        Manifest man, URL url) {
+        Package pkg = getPackage(pkgname);
+        if (pkg != null) {
+            // Package found, so check package sealing.
+            if (pkg.isSealed()) {
+                // Verify that code source URL is the same.
+                if (!pkg.isSealed(url)) {
+                    throw new SecurityException(
+                        "sealing violation: package " + pkgname + " is sealed");
+                }
+            } else {
+                // Make sure we are not attempting to seal the package
+                // at this code source URL.
+                if ((man != null) && isSealed(pkgname, man)) {
+                    throw new SecurityException(
+                        "sealing violation: can't seal package " + pkgname +
+                        ": already loaded");
+                }
+            }
+        }
+        return pkg;
+    }
+
+    /*
      * Defines a Class using the class bytes obtained from the specified
      * Resource. The resulting Class must be resolved before it can be
      * used.
@@ -316,32 +345,23 @@
         if (i != -1) {
             String pkgname = name.substring(0, i);
             // Check if package already loaded.
-            Package pkg = getPackage(pkgname);
             Manifest man = res.getManifest();
-            if (pkg != null) {
-                // Package found, so check package sealing.
-                if (pkg.isSealed()) {
-                    // Verify that code source URL is the same.
-                    if (!pkg.isSealed(url)) {
-                        throw new SecurityException(
-                            "sealing violation: package " + pkgname + " is sealed");
+            if (getAndVerifyPackage(pkgname, man, url) == null) {
+                try {
+                    if (man != null) {
+                        definePackage(pkgname, man, url);
+                    } else {
+                        definePackage(pkgname, null, null, null, null, null, null, null);
                     }
-
-                } else {
-                    // Make sure we are not attempting to seal the package
-                    // at this code source URL.
-                    if ((man != null) && isSealed(pkgname, man)) {
-                        throw new SecurityException(
-                            "sealing violation: can't seal package " + pkgname +
-                            ": already loaded");
+                } catch (IllegalArgumentException iae) {
+                    // parallel-capable class loaders: re-verify in case of a
+                    // race condition
+                    if (getAndVerifyPackage(pkgname, man, url) == null) {
+                        // Should never happen
+                        throw new AssertionError("Cannot find package " +
+                                                 pkgname);
                     }
                 }
-            } else {
-                if (man != null) {
-                    definePackage(pkgname, man, url);
-                } else {
-                    definePackage(pkgname, null, null, null, null, null, null, null);
-                }
             }
         }
         // Now read the class bytes and define the class