diff --git a/common/src/main/java/com/taobao/arthas/common/ReflectException.java b/common/src/main/java/com/taobao/arthas/common/ReflectException.java index a33ee7e212..582d359443 100644 --- a/common/src/main/java/com/taobao/arthas/common/ReflectException.java +++ b/common/src/main/java/com/taobao/arthas/common/ReflectException.java @@ -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; } diff --git a/common/src/main/java/com/taobao/arthas/common/ReflectUtils.java b/common/src/main/java/com/taobao/arthas/common/ReflectUtils.java index 7be111e770..3be73a233c 100644 --- a/common/src/main/java/com/taobao/arthas/common/ReflectUtils.java +++ b/common/src/main/java/com/taobao/arthas/common/ReflectUtils.java @@ -3,7 +3,9 @@ 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 static Class defineClass(String className, byte[] b, ClassLoader loader, 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) { diff --git a/common/src/main/java/com/taobao/arthas/common/UnsafeUtils.java b/common/src/main/java/com/taobao/arthas/common/UnsafeUtils.java new file mode 100644 index 0000000000..d2ccdce639 --- /dev/null +++ b/common/src/main/java/com/taobao/arthas/common/UnsafeUtils.java @@ -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 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; + } +}