Skip to content

Commit

Permalink
Better handling with MethodHandle for Java 11+
Browse files Browse the repository at this point in the history
  • Loading branch information
jeanouii committed Oct 7, 2021
1 parent 925be66 commit 3fcc6a7
Showing 1 changed file with 61 additions and 31 deletions.
92 changes: 61 additions & 31 deletions webbeans-impl/src/main/java/org/apache/webbeans/proxy/Unsafe.java
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ public Unsafe()
catch (Exception e)
{
WebBeansLoggerFacade.getLogger(Unsafe.class)
.info("Cannot get sun.misc.Unsafe - will use newInstance() instead!");
.info("Cannot get sun.misc.Unsafe - will use newInstance() instead!");
return null;
}
});
Expand All @@ -81,8 +81,7 @@ public Unsafe()
theInternalUnsafe.setAccessible(true);
return theInternalUnsafe.get(null);
}
catch (final Exception notJ11OrMore)
{
catch (final Exception notJ11OrMore) {
return unsafe;
}
});
Expand All @@ -102,42 +101,73 @@ public Unsafe()
}
});

try // some j>8, since we have unsafe let's use it
{
try {
final Class<?> rootLoaderClass = Class.forName("java.lang.ClassLoader");
final Method objectFieldOffset = unsafe.getClass().getDeclaredMethod("objectFieldOffset", Field.class);
final Method putBoolean = unsafe.getClass().getDeclaredMethod("putBoolean", Object.class, long.class, boolean.class);
objectFieldOffset.setAccessible(true);
final long accOffset = Long.class.cast(objectFieldOffset.invoke(unsafe, AccessibleObject.class.getDeclaredField("override")));
putBoolean.invoke(unsafe, rootLoaderClass.getDeclaredMethod("defineClass",
new Class[]{String.class, byte[].class, int.class, int.class}),
accOffset, true);
putBoolean.invoke(unsafe, rootLoaderClass
.getDeclaredMethod("defineClass", new Class[]{String.class, byte[].class,
int.class, int.class, ProtectionDomain.class}),
accOffset, true);
try {
final Method getModule = Class.class.getMethod("getModule");
final Object module = getModule.invoke(rootLoaderClass);
if (module != null)
{
final Method isOpen = module.getClass().getMethod("isOpen", String.class);
if (Boolean.class.cast(isOpen.invoke(module, "sun.misc")))
{
oldStyleSetAccessibleDefineClass(rootLoaderClass);
}
else
{
hackSetDefineClassAccessible();
}
} else
{ // very unlikely since we should fall into unamed module
hackSetDefineClassAccessible();
}
}
catch (final NoSuchMethodException nsme)
{ // pre java 9
oldStyleSetAccessibleDefineClass(rootLoaderClass);
}
}
catch (final Exception e)
{
try
{
final Class<?> rootLoaderClass = Class.forName("java.lang.ClassLoader");
rootLoaderClass.getDeclaredMethod(
"defineClass", new Class[] { String.class, byte[].class, int.class, int.class })
.setAccessible(true);
rootLoaderClass.getDeclaredMethod(
"defineClass", new Class[] {
String.class, byte[].class, int.class, int.class, ProtectionDomain.class })
.setAccessible(true); // this produces warning from 11+ and fails on 17+
}
catch (final Exception ex)
{
// no-op
}
hackSetDefineClassAccessible();
}
}
}

private void oldStyleSetAccessibleDefineClass(final Class<?> rootLoaderClass) throws NoSuchMethodException
{
rootLoaderClass.getDeclaredMethod(
"defineClass", new Class[]{String.class, byte[].class, int.class, int.class})
.setAccessible(true);
rootLoaderClass.getDeclaredMethod(
"defineClass", new Class[]{
String.class, byte[].class, int.class, int.class, ProtectionDomain.class})
.setAccessible(true);
}

private void hackSetDefineClassAccessible()
{
try
{
final Class<?> rootLoaderClass = Class.forName("java.lang.ClassLoader");
final Method objectFieldOffset = unsafe.getClass().getDeclaredMethod("objectFieldOffset", Field.class);
final Method putBoolean = unsafe.getClass().getDeclaredMethod("putBoolean", Object.class, long.class, boolean.class);
objectFieldOffset.setAccessible(true);
final long accOffset = Long.class.cast(objectFieldOffset.invoke(unsafe, AccessibleObject.class.getDeclaredField("override")));
putBoolean.invoke(unsafe, rootLoaderClass.getDeclaredMethod("defineClass",
new Class[]{String.class, byte[].class, int.class, int.class}),
accOffset, true);
putBoolean.invoke(unsafe, rootLoaderClass
.getDeclaredMethod("defineClass", new Class[]{String.class, byte[].class,
int.class, int.class, ProtectionDomain.class}),
accOffset, true);
}
catch (final Exception e)
{
// no-op
}
}

/**
* The 'defineClass' method on the ClassLoader is protected, thus we need to invoke it via reflection.
* @return the Class which got loaded in the classloader
Expand Down

0 comments on commit 3fcc6a7

Please sign in to comment.