diff options
author | nickl- <github@jigsoft.co.za> | 2017-10-27 08:10:22 +0200 |
---|---|---|
committer | nickl- <github@jigsoft.co.za> | 2017-11-12 23:49:21 +0200 |
commit | 50dd54dc0552960c80aacded54a9ff7fe0f747f6 (patch) | |
tree | d890ab52e5b95b94b5696a9c8ce6f576d1c8824a | |
parent | af399dbfa005ccde16247b88159cc269e243fb22 (diff) | |
download | javassist-50dd54dc0552960c80aacded54a9ff7fe0f747f6.tar.gz javassist-50dd54dc0552960c80aacded54a9ff7fe0f747f6.zip |
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.
-rw-r--r-- | src/main/javassist/util/proxy/DefineClassHelper.java | 15 | ||||
-rwxr-xr-x | src/main/javassist/util/proxy/SecurityActions.java | 61 |
2 files changed, 64 insertions, 12 deletions
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<Object>() { public Object run() throws + new PrivilegedExceptionAction<TheUnsafe>() { 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<String, List<Method>> methods = + new HashMap<String, List<Method>>(); + + 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<Method>(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*/ } + } } + |