Skip to content

Commit

Permalink
Synchronize the lookup-and-define-class logic in blackbird
Browse files Browse the repository at this point in the history
If blackbird attempts to access/define a new class concurrently,
it can hit a race condition between attempting to access it and
defining it when that fails.  If it does fail, enter a synchronized
block and try again before defining the access class.

Should fix FasterXML#169
  • Loading branch information
josephlbarnett committed May 4, 2022
1 parent a9ec8e2 commit c77b0f0
Showing 1 changed file with 26 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -106,27 +106,34 @@ private static boolean hasFullAccess(MethodHandles.Lookup lookup) {

private static Class<?> accessClassIn(MethodHandles.Lookup lookup) throws IOException, ReflectiveOperationException {
Package pkg = lookup.lookupClass().getPackage();
String accessClassName = pkg.getName() + "." + CLASS_NAME;
ClassLoader lookupClassLoader = lookup.lookupClass().getClassLoader();
try {
return Class.forName(pkg.getName() + "." + CLASS_NAME, true, lookup.lookupClass().getClassLoader());
return Class.forName(accessClassName, true, lookupClassLoader);
} catch (ClassNotFoundException ign) { }
String fqcn = pkg.getName()
.replace('.', '/')
+ "/" + CLASS_NAME;
ByteArrayOutputStream classBytes = new ByteArrayOutputStream(HEADER.length + FOOTER.length + fqcn.length() + 16);
DataOutputStream dataOut = new DataOutputStream(classBytes);
for (int b : HEADER) {
dataOut.writeByte(b);
}
dataOut.writeUTF(fqcn);
for (int b : FOOTER) {
dataOut.writeByte(b);
}
try {
return (Class<?>) DEFINE_CLASS.invokeExact(lookup, classBytes.toByteArray());
} catch (RuntimeException | Error | IOException | ReflectiveOperationException e) {
throw e;
} catch (Throwable e) {
throw new RuntimeException(e);
synchronized (CrossLoaderAccess.class) {
try {
return Class.forName(accessClassName, true, lookupClassLoader);
} catch (ClassNotFoundException ign) { }
String fqcn = pkg.getName()
.replace('.', '/')
+ "/" + CLASS_NAME;
ByteArrayOutputStream classBytes = new ByteArrayOutputStream(HEADER.length + FOOTER.length + fqcn.length() + 16);
DataOutputStream dataOut = new DataOutputStream(classBytes);
for (int b : HEADER) {
dataOut.writeByte(b);
}
dataOut.writeUTF(fqcn);
for (int b : FOOTER) {
dataOut.writeByte(b);
}
try {
return (Class<?>) DEFINE_CLASS.invokeExact(lookup, classBytes.toByteArray());
} catch (RuntimeException | Error | IOException | ReflectiveOperationException e) {
throw e;
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
}
}

0 comments on commit c77b0f0

Please sign in to comment.