]> source.dussan.org Git - javassist.git/commitdiff
Even now Oracle still not happy.
authornickl- <github@jigsoft.co.za>
Fri, 27 Oct 2017 06:10:22 +0000 (08:10 +0200)
committernickl- <github@jigsoft.co.za>
Sun, 12 Nov 2017 21:49:21 +0000 (23:49 +0200)
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.

src/main/javassist/util/proxy/DefineClassHelper.java
src/main/javassist/util/proxy/SecurityActions.java

index aebb5acb4b264356a9dc1debe938f260c723ccba..3ed261e5199c324533d34541661a7ddd623512c2 100644 (file)
@@ -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);
index 4bc10a8a37809434b6d04ca02b78cb347b1ee1b7..574073d06c23e67056c4770bca6442abfcf50345 100755 (executable)
@@ -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*/ }
+    }
 }
+