aboutsummaryrefslogtreecommitdiffstats
path: root/src/main/javassist/util/proxy
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/javassist/util/proxy')
-rw-r--r--src/main/javassist/util/proxy/DefineClassHelper.java240
-rw-r--r--src/main/javassist/util/proxy/DefinePackageHelper.java179
-rwxr-xr-xsrc/main/javassist/util/proxy/SecurityActions.java232
3 files changed, 528 insertions, 123 deletions
diff --git a/src/main/javassist/util/proxy/DefineClassHelper.java b/src/main/javassist/util/proxy/DefineClassHelper.java
index 97c83800..3ed261e5 100644
--- a/src/main/javassist/util/proxy/DefineClassHelper.java
+++ b/src/main/javassist/util/proxy/DefineClassHelper.java
@@ -16,13 +16,11 @@
package javassist.util.proxy;
-import java.io.IOException;
-import java.lang.reflect.Method;
-import java.lang.reflect.Field;
-import java.security.ProtectionDomain;
+import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodHandles.Lookup;
-import sun.misc.Unsafe;
+import java.lang.reflect.Method;
+import java.security.ProtectionDomain;
import javassist.CannotCompileException;
import javassist.bytecode.ClassFile;
@@ -32,39 +30,153 @@ import javassist.bytecode.ClassFile;
*
* @since 3.22
*/
-public class DefineClassHelper {
- private static java.lang.reflect.Method defineClass1 = null;
- private static java.lang.reflect.Method defineClass2 = null;
- private static Unsafe sunMiscUnsafe = null;
-
- static {
- if (ClassFile.MAJOR_VERSION < ClassFile.JAVA_9)
- try {
- Class<?> cl = Class.forName("java.lang.ClassLoader");
- defineClass1 = SecurityActions.getDeclaredMethod(
- cl,
- "defineClass",
- new Class[] { String.class, byte[].class,
- int.class, int.class });
-
- defineClass2 = SecurityActions.getDeclaredMethod(
- cl,
- "defineClass",
- new Class[] { String.class, byte[].class,
- int.class, int.class, ProtectionDomain.class });
+public class DefineClassHelper
+{
+
+ private static enum SecuredPrivileged
+ {
+ JAVA_9 {
+ final class ReferencedUnsafe
+ {
+ private final SecurityActions.TheUnsafe sunMiscUnsafeTheUnsafe;
+ private final MethodHandle defineClass;
+
+ ReferencedUnsafe(SecurityActions.TheUnsafe usf, MethodHandle meth)
+ {
+ this.sunMiscUnsafeTheUnsafe = usf;
+ this.defineClass = meth;
+ }
+
+ Class<?> defineClass(String name, byte[] b, int off, int len,
+ ClassLoader loader, ProtectionDomain protectionDomain)
+ throws ClassFormatError {
+ if (stack.getCallerClass() != SecuredPrivileged.JAVA_9.getClass())
+ throw new IllegalAccessError("Access denied for caller.");
+ try {
+ return (Class<?>) defineClass.invokeWithArguments(
+ sunMiscUnsafeTheUnsafe.theUnsafe,
+ name, b, off, len, loader, protectionDomain);
+ } catch (Throwable e) {
+ if (e instanceof RuntimeException) throw (RuntimeException) e;
+ if (e instanceof ClassFormatError) throw (ClassFormatError) e;
+ throw new ClassFormatError(e.getMessage());
+ }
+ }
+ }
+ private final StackWalker stack = StackWalker
+ .getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE);
+ private final ReferencedUnsafe sunMiscUnsafe = getReferencedUnsafe();
+ private final ReferencedUnsafe getReferencedUnsafe()
+ {
+ if (null != SecuredPrivileged.JAVA_9
+ && stack.getCallerClass() != this.getClass())
+ throw new IllegalAccessError("Access denied for caller.");
+ try {
+ 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);
+ }
}
- catch (Exception e) {
- throw new RuntimeException("cannot initialize");
+
+ @Override
+ public Class<?> defineClass(String name, byte[] b, int off, int len,
+ ClassLoader loader, ProtectionDomain protectionDomain)
+ throws ClassFormatError
+ {
+ if (stack.getCallerClass() != DefineClassHelper.class)
+ throw new IllegalAccessError("Access denied for caller.");
+ return sunMiscUnsafe.defineClass(name, b, off, len, loader,
+ protectionDomain);
}
- else
- try {
- Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
- theUnsafe.setAccessible(true);
- sunMiscUnsafe = (sun.misc.Unsafe)theUnsafe.get(null);
+ },
+ JAVA_7 {
+ private final SecurityActions stack = SecurityActions.stack;
+ private final MethodHandle defineClass = getDefineClassMethodHandle();
+ private final MethodHandle getDefineClassMethodHandle()
+ {
+ if (null != SecuredPrivileged.JAVA_7
+ && stack.getCallerClass() != this.getClass())
+ throw new IllegalAccessError("Access denied for caller.");
+ try {
+ return SecurityActions.getMethodHandle(ClassLoader.class,
+ "defineClass", new Class[] {
+ String.class, byte[].class, int.class, int.class,
+ ProtectionDomain.class
+ });
+ } catch (NoSuchMethodException e) {
+ throw new RuntimeException("cannot initialize", e);
+ }
}
- catch (Throwable t) {}
+
+ @Override
+ protected Class<?> defineClass(String name, byte[] b, int off, int len,
+ ClassLoader loader, ProtectionDomain protectionDomain) throws ClassFormatError
+ {
+ if (stack.getCallerClass() != DefineClassHelper.class)
+ throw new IllegalAccessError("Access denied for caller.");
+ try {
+ return (Class<?>) defineClass.invokeWithArguments(
+ loader, name, b, off, len, protectionDomain);
+ } catch (Throwable e) {
+ if (e instanceof RuntimeException) throw (RuntimeException) e;
+ if (e instanceof ClassFormatError) throw (ClassFormatError) e;
+ throw new ClassFormatError(e.getMessage());
+ }
+ }
+ },
+ JAVA_OTHER {
+ private final Method defineClass = getDefineClassMethod();
+ private final SecurityActions stack = SecurityActions.stack;
+ private final Method getDefineClassMethod() {
+ if (null != SecuredPrivileged.JAVA_OTHER
+ && stack.getCallerClass() != this.getClass())
+ throw new IllegalAccessError("Access denied for caller.");
+ try {
+ return SecurityActions.getDeclaredMethod(ClassLoader.class,
+ "defineClass", new Class[] {
+ String.class, byte[].class, int.class, int.class, ProtectionDomain.class
+ });
+ } catch (NoSuchMethodException e) {
+ throw new RuntimeException("cannot initialize", e);
+ }
+ }
+
+ @Override
+ protected Class<?> defineClass(String name, byte[] b, int off, int len,
+ ClassLoader loader, ProtectionDomain protectionDomain) throws ClassFormatError
+ {
+ if (stack.getCallerClass() != DefineClassHelper.class)
+ throw new IllegalAccessError("Access denied for caller.");
+ try {
+ SecurityActions.setAccessible(defineClass, true);
+ return (Class<?>) defineClass.invoke(loader, new Object[] {
+ name, b, off, len, protectionDomain
+ });
+ } catch (Throwable e) {
+ if (e instanceof ClassFormatError) throw (ClassFormatError) e;
+ if (e instanceof RuntimeException) throw (RuntimeException) e;
+ throw new ClassFormatError(e.getMessage());
+ }
+ finally {
+ SecurityActions.setAccessible(defineClass, false);
+ }
+ }
+
+ };
+
+ protected abstract Class<?> defineClass(String name, byte[] b, int off, int len,
+ ClassLoader loader, ProtectionDomain protectionDomain) throws ClassFormatError;
}
+ private static final SecuredPrivileged privileged = ClassFile.MAJOR_VERSION >= ClassFile.JAVA_9
+ ? SecuredPrivileged.JAVA_9
+ : ClassFile.MAJOR_VERSION >= ClassFile.JAVA_7
+ ? SecuredPrivileged.JAVA_7
+ : SecuredPrivileged.JAVA_OTHER;
+
/**
* Loads a class file by a given class loader.
*
@@ -84,15 +196,18 @@ public class DefineClassHelper {
ProtectionDomain domain, byte[] bcode)
throws CannotCompileException
{
- if (ClassFile.MAJOR_VERSION >= ClassFile.JAVA_9)
- if (sunMiscUnsafe != null)
- try {
- return sunMiscUnsafe.defineClass(className, bcode, 0, bcode.length,
- loader, domain);
- }
- catch (Throwable t2) {}
-
- return toClass2(className, loader, domain, bcode);
+ try {
+ return privileged.defineClass(className, bcode, 0, bcode.length, loader, domain);
+ }
+ catch (RuntimeException e) {
+ throw e;
+ }
+ catch (ClassFormatError e) {
+ throw new CannotCompileException(e.getCause());
+ }
+ catch (Exception e) {
+ throw new CannotCompileException(e);
+ }
}
/**
@@ -113,44 +228,5 @@ public class DefineClassHelper {
}
}
- private static Class<?> toClass2(String cname, ClassLoader loader,
- ProtectionDomain domain, byte[] bcode)
- throws CannotCompileException
- {
- try {
- Method method;
- Object[] args;
- if (domain == null) {
- method = defineClass1;
- args = new Object[] { cname, bcode, Integer.valueOf(0),
- Integer.valueOf(bcode.length) };
- }
- else {
- method = defineClass2;
- args = new Object[] { cname, bcode, Integer.valueOf(0),
- Integer.valueOf(bcode.length), domain };
- }
-
- return toClass3(method, loader, args);
- }
- catch (RuntimeException e) {
- throw e;
- }
- catch (java.lang.reflect.InvocationTargetException e) {
- throw new CannotCompileException(e.getTargetException());
- }
- catch (Exception e) {
- throw new CannotCompileException(e);
- }
- }
-
- private static synchronized
- Class<?> toClass3(Method method, ClassLoader loader, Object[] args)
- throws Exception
- {
- SecurityActions.setAccessible(method, true);
- Class<?> clazz = (Class<?>)method.invoke(loader, args);
- SecurityActions.setAccessible(method, false);
- return clazz;
- }
+ private DefineClassHelper() {}
}
diff --git a/src/main/javassist/util/proxy/DefinePackageHelper.java b/src/main/javassist/util/proxy/DefinePackageHelper.java
new file mode 100644
index 00000000..1fe0bd61
--- /dev/null
+++ b/src/main/javassist/util/proxy/DefinePackageHelper.java
@@ -0,0 +1,179 @@
+/*
+ * Javassist, a Java-bytecode translator toolkit.
+ * Copyright (C) 1999- Shigeru Chiba. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. Alternatively, the contents of this file may be used under
+ * the terms of the GNU Lesser General Public License Version 2.1 or later,
+ * or the Apache License Version 2.0.
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ */
+
+package javassist.util.proxy;
+
+import java.lang.invoke.MethodHandle;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.net.URL;
+
+import javassist.CannotCompileException;
+import javassist.CtClass;
+import javassist.bytecode.ClassFile;
+
+/**
+ * Helper class for invoking {@link ClassLoader#defineClass(String,byte[],int,int)}.
+ *
+ * @since 3.22
+ */
+public class DefinePackageHelper
+{
+
+ private static enum SecuredPrivileged
+ {
+ JAVA_9 {
+ // definePackage has been discontinued for JAVA 9
+ @Override
+ protected Package definePackage(ClassLoader loader, String name, String specTitle,
+ String specVersion, String specVendor, String implTitle, String implVersion,
+ String implVendor, URL sealBase) throws IllegalArgumentException
+ {
+ throw new RuntimeException("define package has been disabled for jigsaw");
+ }
+ },
+ JAVA_7 {
+ private final SecurityActions stack = SecurityActions.stack;
+ private final MethodHandle definePackage = getDefinePackageMethodHandle();
+ private MethodHandle getDefinePackageMethodHandle()
+ {
+ if (stack.getCallerClass() != this.getClass())
+ throw new IllegalAccessError("Access denied for caller.");
+ try {
+ return SecurityActions.getMethodHandle(ClassLoader.class,
+ "definePackage", new Class[] {
+ String.class, String.class, String.class, String.class,
+ String.class, String.class, String.class, URL.class
+ });
+ } catch (NoSuchMethodException e) {
+ throw new RuntimeException("cannot initialize", e);
+ }
+ }
+
+ @Override
+ protected Package definePackage(ClassLoader loader, String name, String specTitle,
+ String specVersion, String specVendor, String implTitle, String implVersion,
+ String implVendor, URL sealBase) throws IllegalArgumentException {
+ if (stack.getCallerClass() != DefinePackageHelper.class)
+ throw new IllegalAccessError("Access denied for caller.");
+ try {
+ return (Package) definePackage.invokeWithArguments(loader, name, specTitle,
+ specVersion, specVendor, implTitle, implVersion, implVendor, sealBase);
+ } catch (Throwable e) {
+ if (e instanceof IllegalArgumentException) throw (IllegalArgumentException) e;
+ if (e instanceof RuntimeException) throw (RuntimeException) e;
+ }
+ return null;
+ }
+ },
+ JAVA_OTHER {
+ private final SecurityActions stack = SecurityActions.stack;
+ private final Method definePackage = getDefinePackageMethod();
+ private Method getDefinePackageMethod()
+ {
+ if (stack.getCallerClass() != this.getClass())
+ throw new IllegalAccessError("Access denied for caller.");
+ try {
+ return SecurityActions.getDeclaredMethod(ClassLoader.class,
+ "definePackage", new Class[] {
+ String.class, String.class, String.class, String.class,
+ String.class, String.class, String.class, URL.class
+ });
+ } catch (NoSuchMethodException e) {
+ throw new RuntimeException("cannot initialize", e);
+ }
+ }
+
+ @Override
+ protected Package definePackage(ClassLoader loader, String name, String specTitle,
+ String specVersion, String specVendor, String implTitle, String implVersion,
+ String implVendor, URL sealBase) throws IllegalArgumentException
+ {
+ if (stack.getCallerClass() != DefinePackageHelper.class)
+ throw new IllegalAccessError("Access denied for caller.");
+ try {
+ definePackage.setAccessible(true);
+ return (Package) definePackage.invoke(loader, new Object[] {
+ name, specTitle, specVersion, specVendor, implTitle,
+ implVersion, implVendor, sealBase
+ });
+ } catch (Throwable e) {
+ if (e instanceof InvocationTargetException) {
+ Throwable t = ((InvocationTargetException) e).getTargetException();
+ if (t instanceof IllegalArgumentException)
+ throw (IllegalArgumentException) t;
+ }
+ if (e instanceof RuntimeException) throw (RuntimeException) e;
+ }
+ finally {
+ definePackage.setAccessible(false);
+ }
+ return null;
+ }
+ };
+
+ protected abstract Package definePackage(ClassLoader loader, String name, String specTitle,
+ String specVersion, String specVendor, String implTitle, String implVersion,
+ String implVendor, URL sealBase) throws IllegalArgumentException;
+ }
+
+ private static final SecuredPrivileged privileged = ClassFile.MAJOR_VERSION >= ClassFile.JAVA_9
+ ? SecuredPrivileged.JAVA_9
+ : ClassFile.MAJOR_VERSION >= ClassFile.JAVA_7
+ ? SecuredPrivileged.JAVA_7
+ : SecuredPrivileged.JAVA_OTHER;
+
+
+ /**
+ * Defines a new package. If the package is already defined, this method
+ * performs nothing.
+ *
+ * <p>You do not necessarily need to
+ * call this method. If this method is called, then
+ * <code>getPackage()</code> on the <code>Class</code> object returned
+ * by <code>toClass()</code> will return a non-null object.</p>
+ *
+ * <p>The jigsaw module introduced by Java 9 has broken this method.
+ * In Java 9 or later, the VM argument
+ * <code>--add-opens java.base/java.lang=ALL-UNNAMED</code>
+ * has to be given to the JVM so that this method can run.
+ * </p>
+ *
+ * @param loader the class loader passed to <code>toClass()</code> or
+ * the default one obtained by <code>getClassLoader()</code>.
+ * @param name the package name.
+ * @see #getClassLoader()
+ * @see #toClass(CtClass)
+ * @see CtClass#toClass() */
+ public static void definePackage(String className, ClassLoader loader)
+ throws CannotCompileException
+ {
+ try {
+ privileged.definePackage(loader, className,
+ null, null, null, null, null, null, null);
+ }
+ catch (IllegalArgumentException e) {
+ // if the package is already defined, an IllegalArgumentException
+ // is thrown.
+ return;
+ }
+ catch (Exception e) {
+ throw new CannotCompileException(e);
+ }
+ }
+
+ private DefinePackageHelper() {}
+}
diff --git a/src/main/javassist/util/proxy/SecurityActions.java b/src/main/javassist/util/proxy/SecurityActions.java
index ed1ec981..acb89c8d 100755
--- a/src/main/javassist/util/proxy/SecurityActions.java
+++ b/src/main/javassist/util/proxy/SecurityActions.java
@@ -15,6 +15,8 @@
*/
package javassist.util.proxy;
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
@@ -23,46 +25,99 @@ 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;
-class SecurityActions {
- static Method[] getDeclaredMethods(final Class clazz) {
+import javassist.bytecode.ClassFile;
+
+class SecurityActions extends SecurityManager
+{
+ public static final SecurityActions stack = new SecurityActions();
+ /**
+ * Since Java 9 abruptly removed <code>Reflection.getCallerClass()</code>
+ * in favour of <code>StackWalker</code> we are left having to find a
+ * solution for the older versions without upsetting the new compiler.
+ *
+ * The member scoped function <code>getClassContext()</code>
+ * available as a <code>SecurityManager</code> sibling remains
+ * functional across all versions, for now.
+ *
+ * @return represents the declaring class of the method that invoked
+ * the method that called this or idx 2 on the stack trace.
+ * @since 3.23 */
+ public Class<?> getCallerClass()
+ {
+ return getClassContext()[2];
+ }
+
+
+ static Method[] getDeclaredMethods(final Class<?> clazz)
+ {
if (System.getSecurityManager() == null)
return clazz.getDeclaredMethods();
else {
- return (Method[]) AccessController
- .doPrivileged(new PrivilegedAction() {
- public Object run() {
- return clazz.getDeclaredMethods();
- }
- });
+ return AccessController.doPrivileged(
+ new PrivilegedAction<Method[]>() {
+ public Method[] run() {
+ return clazz.getDeclaredMethods();
+ }
+ });
}
}
- static Constructor[] getDeclaredConstructors(final Class clazz) {
+ static Constructor<?>[] getDeclaredConstructors(final Class<?> clazz)
+ {
if (System.getSecurityManager() == null)
return clazz.getDeclaredConstructors();
else {
- return (Constructor[]) AccessController
- .doPrivileged(new PrivilegedAction() {
- public Object run() {
- return clazz.getDeclaredConstructors();
- }
- });
+ return AccessController.doPrivileged(
+ new PrivilegedAction<Constructor<?>[]>() {
+ public Constructor<?>[] run() {
+ return clazz.getDeclaredConstructors();
+ }
+ });
}
}
- static Method getDeclaredMethod(final Class clazz, final String name,
- final Class[] types) throws NoSuchMethodException {
+ static MethodHandle getMethodHandle(final Class<?> clazz, final
+ String name, final Class<?>[] params) throws NoSuchMethodException
+ {
+ try {
+ return AccessController.doPrivileged(
+ new PrivilegedExceptionAction<MethodHandle>() {
+ public MethodHandle run() throws IllegalAccessException,
+ NoSuchMethodException, SecurityException {
+ Method rmet = clazz.getDeclaredMethod(name, params);
+ rmet.setAccessible(true);
+ MethodHandle meth = MethodHandles.lookup().unreflect(rmet);
+ rmet.setAccessible(false);
+ return meth;
+ }
+ });
+ }
+ catch (PrivilegedActionException e) {
+ if (e.getCause() instanceof NoSuchMethodException)
+ throw (NoSuchMethodException) e.getCause();
+ throw new RuntimeException(e.getCause());
+ }
+ }
+
+ static Method getDeclaredMethod(final Class<?> clazz, final String name,
+ final Class<?>[] types) throws NoSuchMethodException
+ {
if (System.getSecurityManager() == null)
return clazz.getDeclaredMethod(name, types);
else {
try {
- return (Method) AccessController
- .doPrivileged(new PrivilegedExceptionAction() {
- public Object run() throws Exception {
- return clazz.getDeclaredMethod(name, types);
- }
- });
+ return AccessController.doPrivileged(
+ new PrivilegedExceptionAction<Method>() {
+ public Method run() throws Exception {
+ return clazz.getDeclaredMethod(name, types);
+ }
+ });
}
catch (PrivilegedActionException e) {
if (e.getCause() instanceof NoSuchMethodException)
@@ -73,20 +128,20 @@ class SecurityActions {
}
}
- static Constructor getDeclaredConstructor(final Class clazz,
- final Class[] types)
+ static Constructor<?> getDeclaredConstructor(final Class<?> clazz,
+ final Class<?>[] types)
throws NoSuchMethodException
{
if (System.getSecurityManager() == null)
return clazz.getDeclaredConstructor(types);
else {
try {
- return (Constructor) AccessController
- .doPrivileged(new PrivilegedExceptionAction() {
- public Object run() throws Exception {
- return clazz.getDeclaredConstructor(types);
- }
- });
+ return AccessController.doPrivileged(
+ new PrivilegedExceptionAction<Constructor<?>>() {
+ public Constructor<?> run() throws Exception {
+ return clazz.getDeclaredConstructor(types);
+ }
+ });
}
catch (PrivilegedActionException e) {
if (e.getCause() instanceof NoSuchMethodException)
@@ -98,12 +153,13 @@ class SecurityActions {
}
static void setAccessible(final AccessibleObject ao,
- final boolean accessible) {
+ final boolean accessible)
+ {
if (System.getSecurityManager() == null)
ao.setAccessible(accessible);
else {
- AccessController.doPrivileged(new PrivilegedAction() {
- public Object run() {
+ AccessController.doPrivileged(new PrivilegedAction<Void>() {
+ public Void run() {
ao.setAccessible(accessible);
return null;
}
@@ -118,19 +174,113 @@ class SecurityActions {
fld.set(target, value);
else {
try {
- AccessController.doPrivileged(new PrivilegedExceptionAction() {
- public Object run() throws Exception {
- fld.set(target, value);
- return null;
- }
- });
+ AccessController.doPrivileged(
+ new PrivilegedExceptionAction<Void>() {
+ public Void run() throws Exception {
+ fld.set(target, value);
+ return null;
+ }
+ });
}
catch (PrivilegedActionException e) {
if (e.getCause() instanceof NoSuchMethodException)
throw (IllegalAccessException) e.getCause();
-
throw new RuntimeException(e.getCause());
}
}
}
+
+ static TheUnsafe getSunMiscUnsafeAnonymously() throws ClassNotFoundException
+ {
+ try {
+ return AccessController.doPrivileged(
+ 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);
+ TheUnsafe usf = stack.new TheUnsafe(unsafe, theUnsafe.get(null));
+ theUnsafe.setAccessible(false);
+ disableWarning(usf);
+ return usf;
+ }
+ });
+ }
+ catch (PrivilegedActionException e) {
+ if (e.getCause() instanceof ClassNotFoundException)
+ throw (ClassNotFoundException) e.getCause();
+ if (e.getCause() instanceof NoSuchFieldException)
+ throw new ClassNotFoundException("No such instance.", e.getCause());
+ if (e.getCause() instanceof IllegalAccessException
+ || e.getCause() instanceof IllegalAccessException
+ || e.getCause() instanceof SecurityException)
+ throw new ClassNotFoundException("Security denied access.", e.getCause());
+ throw new RuntimeException(e.getCause());
+ }
+ }
+ /**
+ * _The_ Notorious sun.misc.Unsafe in all its glory, but anonymous
+ * so as not to attract unwanted attention. Kept in two separate
+ * parts it manages to avoid detection from linker/compiler/general
+ * complainers and those. This functionality will vanish from the
+ * JDK soon but in the meantime it shouldn't be an obstacle.
+ *
+ * All exposed methods are cached in a dictionary with overloaded
+ * methods collected under their corresponding keys. Currently the
+ * implementation assumes there is only one, if you need find a
+ * need there will have to be a compare.
+ * @since 3.23 */
+ 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;
+ }
+ }
+ /**
+ * Java 9 now complains about every privileged action regardless.
+ * Displaying warnings of "illegal usage" and then instructing users
+ * to go hassle the maintainers in order to have it fixed.
+ * Making it hush for now, see all fixed.
+ * @param tu theUnsafe that'll fix it */
+ 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*/ }
+ }
}
+