From: nickl- Date: Fri, 27 Oct 2017 06:10:22 +0000 (+0200) Subject: Even now Oracle still not happy. X-Git-Tag: rel_3_23_0_ga~9^2~3 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=50dd54dc0552960c80aacded54a9ff7fe0f747f6;p=javassist.git Even now Oracle still not happy. Runtime still throws warnings illegal actions even after all that, there's just no logic to it. We can use Unsafe but don't touch setAccessible. O well might as well enjoy Unsafe while we still can. Wrapped the Unsafe and added method cache with varargs method for invoke calls. Can still do a lot with it but it does what it needs to for now. --- diff --git a/src/main/javassist/util/proxy/DefineClassHelper.java b/src/main/javassist/util/proxy/DefineClassHelper.java index aebb5acb..3ed261e5 100644 --- a/src/main/javassist/util/proxy/DefineClassHelper.java +++ b/src/main/javassist/util/proxy/DefineClassHelper.java @@ -38,10 +38,10 @@ public class DefineClassHelper JAVA_9 { final class ReferencedUnsafe { - private final Object sunMiscUnsafeTheUnsafe; + private final SecurityActions.TheUnsafe sunMiscUnsafeTheUnsafe; private final MethodHandle defineClass; - ReferencedUnsafe(Object usf, MethodHandle meth) + ReferencedUnsafe(SecurityActions.TheUnsafe usf, MethodHandle meth) { this.sunMiscUnsafeTheUnsafe = usf; this.defineClass = meth; @@ -54,7 +54,7 @@ public class DefineClassHelper throw new IllegalAccessError("Access denied for caller."); try { return (Class) defineClass.invokeWithArguments( - sunMiscUnsafeTheUnsafe, + sunMiscUnsafeTheUnsafe.theUnsafe, name, b, off, len, loader, protectionDomain); } catch (Throwable e) { if (e instanceof RuntimeException) throw (RuntimeException) e; @@ -72,12 +72,9 @@ public class DefineClassHelper && stack.getCallerClass() != this.getClass()) throw new IllegalAccessError("Access denied for caller."); try { - Object usf = SecurityActions.getSunMiscUnsafeAnonymously(); - MethodHandle meth = SecurityActions.getMethodHandle(ClassLoader.class, - "defineClass", new Class[] { - String.class, byte[].class, int.class, int.class, - ProtectionDomain.class - }); + SecurityActions.TheUnsafe usf = SecurityActions.getSunMiscUnsafeAnonymously(); + MethodHandle meth = MethodHandles.lookup() + .unreflect(usf.methods.get("defineClass").get(0)); return new ReferencedUnsafe(usf, meth); } catch (Throwable e) { throw new RuntimeException("cannot initialize", e); diff --git a/src/main/javassist/util/proxy/SecurityActions.java b/src/main/javassist/util/proxy/SecurityActions.java index 4bc10a8a..574073d0 100755 --- a/src/main/javassist/util/proxy/SecurityActions.java +++ b/src/main/javassist/util/proxy/SecurityActions.java @@ -25,6 +25,14 @@ import java.security.AccessController; import java.security.PrivilegedAction; import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javassist.bytecode.ClassFile; + class SecurityActions extends SecurityManager { public static final SecurityActions stack = new SecurityActions(); @@ -170,18 +178,19 @@ class SecurityActions extends SecurityManager } } - static Object getSunMiscUnsafeAnonymously() throws ClassNotFoundException + static TheUnsafe getSunMiscUnsafeAnonymously() throws ClassNotFoundException { try { return AccessController.doPrivileged( - new PrivilegedExceptionAction() { public Object run() throws + new PrivilegedExceptionAction() { public TheUnsafe run() throws ClassNotFoundException, NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException { Class unsafe = Class.forName("sun.misc.Unsafe"); Field theUnsafe = unsafe.getDeclaredField("theUnsafe"); theUnsafe.setAccessible(true); - Object usf = theUnsafe.get(null); + TheUnsafe usf = stack.new TheUnsafe(unsafe, theUnsafe.get(null)); theUnsafe.setAccessible(false); + disableWarning(usf); return usf; } }); @@ -198,4 +207,50 @@ class SecurityActions extends SecurityManager throw new RuntimeException(e.getCause()); } } + class TheUnsafe + { + final Class unsafe; + final Object theUnsafe; + final Map> methods = + new HashMap>(); + + TheUnsafe(Class c, Object o) + { + this.unsafe = c; + this.theUnsafe = o; + for (Method m: unsafe.getDeclaredMethods()) { + if (!methods.containsKey(m.getName())) { + methods.put(m.getName(), Collections.singletonList(m)); + continue; + } + if (methods.get(m.getName()).size() == 1) + methods.put(m.getName(), + new ArrayList(methods.get(m.getName()))); + methods.get(m.getName()).add(m); + } + } + + private Method getM(String name, Object[] o) + { + return methods.get(name).get(0); + } + + public Object call(String name, Object... args) + { + try { + return getM(name, args).invoke(theUnsafe, args); + } catch (Throwable t) {t.printStackTrace();} + return null; + } + } + static void disableWarning(TheUnsafe tu) { + try { + if (ClassFile.MAJOR_VERSION < ClassFile.JAVA_9) + return; + Class cls = Class.forName("jdk.internal.module.IllegalAccessLogger"); + Field logger = cls.getDeclaredField("logger"); + tu.call("putObjectVolatile", cls, tu.call("staticFieldOffset", logger), null); + } catch (Exception e) { /*swallow*/ } + } } +