Protect against a race condition when defining packages
LaunchedURLClassLoader preemptively defines the package for any classes that it attempts to load so that the manifest from a nested jar is correctly associated with the package. This can lead to a race where the package is defined on two threads in parallel, resulting in an IllegalArgumentException being thrown. This problem was manifesting itself as a NoClassDefFoundError. If the initialization of a class failed due to the above-described IllegalArgumentException, subsequent attempts to use that class would then fail with a NoClassDefFoundError. This commit updates LaunchedURLClassLoader to catch the IllegalArgumentException and then double-check that the package has already been defined. This approach, including thrown an AssertionError when the second check fails, is modelled on the approach taken by URLClassLoader. Closes gh-5464
This commit is contained in:
parent
6be92675c2
commit
1d099035b1
|
@ -73,7 +73,19 @@ public class LaunchedURLClassLoader extends URLClassLoader {
|
|||
throws ClassNotFoundException {
|
||||
Handler.setUseFastConnectionExceptions(true);
|
||||
try {
|
||||
definePackageIfNecessary(name);
|
||||
try {
|
||||
definePackageIfNecessary(name);
|
||||
}
|
||||
catch (IllegalArgumentException ex) {
|
||||
// Tolerate race condition due to being parallel capable
|
||||
if (getPackage(name) == null) {
|
||||
// This should never happen as the IllegalArgumentException indicates
|
||||
// that the package has already been defined and, therefore,
|
||||
// getPackage(name) should not return null.
|
||||
throw new AssertionError("Package " + name + " has already been "
|
||||
+ "defined but it could not be found");
|
||||
}
|
||||
}
|
||||
return super.loadClass(name, resolve);
|
||||
}
|
||||
finally {
|
||||
|
@ -92,7 +104,20 @@ public class LaunchedURLClassLoader extends URLClassLoader {
|
|||
if (lastDot >= 0) {
|
||||
String packageName = className.substring(0, lastDot);
|
||||
if (getPackage(packageName) == null) {
|
||||
definePackage(packageName);
|
||||
try {
|
||||
definePackage(packageName);
|
||||
}
|
||||
catch (IllegalArgumentException ex) {
|
||||
// Tolerate race condition due to being parallel capable
|
||||
if (getPackage(packageName) == null) {
|
||||
// This should never happen as the IllegalArgumentException
|
||||
// indicates that the package has already been defined and,
|
||||
// therefore, getPackage(name) should not have returned null.
|
||||
throw new AssertionError(
|
||||
"Package " + packageName + " has already been defined "
|
||||
+ "but it could not be found");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue