diff options
Diffstat (limited to 'src/main/javassist/util/proxy')
-rw-r--r-- | src/main/javassist/util/proxy/DefineClassHelper.java | 240 | ||||
-rw-r--r-- | src/main/javassist/util/proxy/DefinePackageHelper.java | 179 | ||||
-rwxr-xr-x | src/main/javassist/util/proxy/SecurityActions.java | 232 |
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*/ } + } } + |