mirror of
https://github.com/alibaba/arthas.git
synced 2024-04-21 10:21:39 +00:00
use MethodHandles.Lookup IMPL_LOOKUP to support define class after jdk 17. #2659
This commit is contained in:
@@ -6,7 +6,7 @@ public class ReflectException extends RuntimeException {
|
||||
private Throwable cause;
|
||||
|
||||
public ReflectException(Throwable cause) {
|
||||
super(cause.getClass().getName() + "-->" + cause.getMessage());
|
||||
super(cause != null ? cause.getClass().getName() + "-->" + cause.getMessage() : "");
|
||||
this.cause = cause;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,9 @@ import java.beans.BeanInfo;
|
||||
import java.beans.IntrospectionException;
|
||||
import java.beans.Introspector;
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodHandles.Lookup;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
@@ -429,6 +431,29 @@ public class ReflectUtils {
|
||||
|
||||
Class c = null;
|
||||
|
||||
// 在 jdk 17之后,需要hack方式来调用 #2659
|
||||
if (c == null && classLoaderDefineClassMethod != null) {
|
||||
Lookup implLookup = UnsafeUtils.implLookup();
|
||||
MethodHandle unreflect = implLookup.unreflect(classLoaderDefineClassMethod);
|
||||
|
||||
if (protectionDomain == null) {
|
||||
protectionDomain = PROTECTION_DOMAIN;
|
||||
}
|
||||
try {
|
||||
c = (Class) unreflect.invoke(loader, className, b, 0, b.length, protectionDomain);
|
||||
} catch (InvocationTargetException ex) {
|
||||
throw new ReflectException(ex.getTargetException());
|
||||
} catch (Throwable ex) {
|
||||
// Fall through if setAccessible fails with InaccessibleObjectException on JDK
|
||||
// 9+
|
||||
// (on the module path and/or with a JVM bootstrapped with
|
||||
// --illegal-access=deny)
|
||||
if (!ex.getClass().getName().endsWith("InaccessibleObjectException")) {
|
||||
throw new ReflectException(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Preferred option: JDK 9+ Lookup.defineClass API if ClassLoader matches
|
||||
if (contextClass != null && contextClass.getClassLoader() == loader && privateLookupInMethod != null
|
||||
&& lookupDefineClassMethod != null) {
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
package com.taobao.arthas.common;
|
||||
|
||||
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
import sun.misc.Unsafe;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author hengyunabc 2023-09-21
|
||||
*
|
||||
*/
|
||||
public class UnsafeUtils {
|
||||
public static final Unsafe UNSAFE;
|
||||
private static MethodHandles.Lookup IMPL_LOOKUP;
|
||||
|
||||
static {
|
||||
Unsafe unsafe = null;
|
||||
try {
|
||||
Field theUnsafeField = Unsafe.class.getDeclaredField("theUnsafe");
|
||||
theUnsafeField.setAccessible(true);
|
||||
unsafe = (Unsafe) theUnsafeField.get(null);
|
||||
} catch (Throwable ignored) {
|
||||
// ignored
|
||||
}
|
||||
UNSAFE = unsafe;
|
||||
}
|
||||
|
||||
public static MethodHandles.Lookup implLookup() {
|
||||
if (IMPL_LOOKUP == null) {
|
||||
Class<MethodHandles.Lookup> lookupClass = MethodHandles.Lookup.class;
|
||||
|
||||
try {
|
||||
Field implLookupField = lookupClass.getDeclaredField("IMPL_LOOKUP");
|
||||
long offset = UNSAFE.staticFieldOffset(implLookupField);
|
||||
IMPL_LOOKUP = (MethodHandles.Lookup) UNSAFE.getObject(UNSAFE.staticFieldBase(implLookupField), offset);
|
||||
} catch (Throwable e) {
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
return IMPL_LOOKUP;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user