summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--build.xml3
-rw-r--r--javassist.jarbin729051 -> 740722 bytes
-rw-r--r--src/main/javassist/ClassPool.java71
-rw-r--r--src/main/javassist/CtClassType.java16
-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
-rw-r--r--src/test/javassist/JvstTest.java8
-rw-r--r--src/test/javassist/JvstTest5.java46
-rw-r--r--src/test/test/javassist/proxy/TestSecuredPrivileged.java281
-rw-r--r--src/test/test1/FieldInit.java7
-rw-r--r--src/test/test5/InnerModifier2.java13
12 files changed, 903 insertions, 193 deletions
diff --git a/build.xml b/build.xml
index 788d417d..38a2cc8d 100644
--- a/build.xml
+++ b/build.xml
@@ -17,7 +17,7 @@
<property name="build.classes.dir" value="${build.dir}/classes"/>
<property name="test.src.dir" value="${basedir}/src/test"/>
<property name="test.build.dir" value="${build.dir}/test-classes"/>
- <property name="test.run.dir" value="${basedir}/runtest"/>
+ <property name="test.run.dir" value="${build.dir}/runtest"/>
<property name="test.reports.dir" value = "${build.dir}/test-output"/>
<property name="run.dir" value="${build.classes.dir}"/>
@@ -219,7 +219,6 @@ Copyright (C) 1999- Shigeru Chiba. All Rights Reserved.</i>]]></bottom>
<target name="clean">
<delete dir="html"/>
- <delete dir="${test.run.dir}" />
<delete dir="${build.dir}"/>
<delete file="${target.jar}"/>
<delete file="${dist-version}.zip"/>
diff --git a/javassist.jar b/javassist.jar
index 915b45a6..78328e63 100644
--- a/javassist.jar
+++ b/javassist.jar
Binary files differ
diff --git a/src/main/javassist/ClassPool.java b/src/main/javassist/ClassPool.java
index 89a0067e..60055992 100644
--- a/src/main/javassist/ClassPool.java
+++ b/src/main/javassist/ClassPool.java
@@ -21,19 +21,16 @@ import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
-import java.lang.reflect.Method;
import java.net.URL;
-import java.security.AccessController;
-import java.security.PrivilegedActionException;
-import java.security.PrivilegedExceptionAction;
import java.security.ProtectionDomain;
-import java.util.Hashtable;
-import java.util.Iterator;
import java.util.ArrayList;
import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Iterator;
import javassist.bytecode.ClassFile;
import javassist.bytecode.Descriptor;
+import javassist.util.proxy.DefinePackageHelper;
/**
* A container of <code>CtClass</code> objects.
@@ -69,28 +66,8 @@ import javassist.bytecode.Descriptor;
* @see javassist.CtClass
* @see javassist.ClassPath
*/
+@SuppressWarnings({"unchecked", "rawtypes"})
public class ClassPool {
- private static java.lang.reflect.Method definePackage = null;
-
- static {
- if (ClassFile.MAJOR_VERSION < ClassFile.JAVA_9)
- try {
- AccessController.doPrivileged(new PrivilegedExceptionAction(){
- public Object run() throws Exception{
- Class cl = Class.forName("java.lang.ClassLoader");
- definePackage = cl.getDeclaredMethod("definePackage",
- new Class[] { String.class, String.class, String.class,
- String.class, String.class, String.class,
- String.class, java.net.URL.class });
- return null;
- }
- });
- }
- catch (PrivilegedActionException pae) {
- throw new RuntimeException("cannot initialize ClassPool",
- pae.getException());
- }
- }
/**
* Determines the search order.
@@ -321,7 +298,7 @@ public class ClassPool {
* @see #importPackage(String)
* @since 3.1
*/
- public Iterator getImportedPackages() {
+ public Iterator<String> getImportedPackages() {
return importedPackages.iterator();
}
@@ -1175,43 +1152,7 @@ public class ClassPool {
public void makePackage(ClassLoader loader, String name)
throws CannotCompileException
{
- if (definePackage == null)
- throw new CannotCompileException("give the JVM --add-opens");
-
- Object[] args = new Object[] {
- name, null, null, null, null, null, null, null };
- Throwable t;
- try {
- makePackage2(definePackage, loader, args);
- return;
- }
- catch (java.lang.reflect.InvocationTargetException e) {
- t = e.getTargetException();
- if (t == null)
- t = e;
- else if (t instanceof IllegalArgumentException) {
- // if the package is already defined, an IllegalArgumentException
- // is thrown.
- return;
- }
- }
- catch (Exception e) {
- t = e;
- }
-
- throw new CannotCompileException(t);
+ DefinePackageHelper.definePackage(name, loader);
}
- private static synchronized Object makePackage2(Method method,
- ClassLoader loader, Object[] args)
- throws Exception
- {
- method.setAccessible(true);
- try {
- return method.invoke(loader, args);
- }
- finally {
- method.setAccessible(false);
- }
- }
}
diff --git a/src/main/javassist/CtClassType.java b/src/main/javassist/CtClassType.java
index 0c2f775e..3791b5fb 100644
--- a/src/main/javassist/CtClassType.java
+++ b/src/main/javassist/CtClassType.java
@@ -446,9 +446,19 @@ class CtClassType extends CtClass {
int acc = cf.getAccessFlags();
acc = AccessFlag.clear(acc, AccessFlag.SUPER);
int inner = cf.getInnerAccessFlags();
- if (inner != -1 && (inner & AccessFlag.STATIC) != 0)
- acc |= AccessFlag.STATIC;
-
+ if (inner != -1) {
+ if ((inner & AccessFlag.STATIC) != 0)
+ acc |= AccessFlag.STATIC;
+ if ((inner & AccessFlag.PUBLIC) != 0)
+ acc |= AccessFlag.PUBLIC;
+ else {
+ acc &= ~AccessFlag.PUBLIC; //clear PUBLIC
+ if ((inner & AccessFlag.PROTECTED) != 0)
+ acc |= AccessFlag.PROTECTED;
+ else if ((inner & AccessFlag.PRIVATE) != 0)
+ acc |= AccessFlag.PRIVATE;
+ }
+ }
return AccessFlag.toModifier(acc);
}
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*/ }
+ }
}
+
diff --git a/src/test/javassist/JvstTest.java b/src/test/javassist/JvstTest.java
index c6825fd0..d28c0654 100644
--- a/src/test/javassist/JvstTest.java
+++ b/src/test/javassist/JvstTest.java
@@ -103,6 +103,10 @@ public class JvstTest extends JvstTestRoot {
cc.addField(f2);
CtField f3 = CtField.make("public int f3;", cc);
cc.addField(f3);
+ CtField f4 = CtField.make("public int f4 = this.f2 + 3;", cc);
+ cc.addField(f4);
+ CtField fi = CtField.make("public test1.FieldInit.FI fi = new test1.FieldInit.FI(this);", cc);
+ cc.addField(fi);
testFieldInitHash = f1.hashCode();
cc.writeFile();
Object obj = make(cc.getName());
@@ -112,6 +116,10 @@ public class JvstTest extends JvstTestRoot {
assertEquals(3, value2);
int value3 = obj.getClass().getField("f3").getInt(obj);
assertEquals(0, value3);
+ int value4 = obj.getClass().getField("f4").getInt(obj);
+ assertEquals(6, value4);
+ Object obfi = obj.getClass().getField("fi").get(obj);
+ assertTrue(obfi.getClass().getField("fi").get(obfi) == obj);
}
/* test CodeIterator.insertExGap().
diff --git a/src/test/javassist/JvstTest5.java b/src/test/javassist/JvstTest5.java
index 578abfb2..346263cb 100644
--- a/src/test/javassist/JvstTest5.java
+++ b/src/test/javassist/JvstTest5.java
@@ -344,6 +344,52 @@ public class JvstTest5 extends JvstTestRoot {
assertEquals(Modifier.PUBLIC, ica4.accessFlags(i5));
}
+ public void testInnerClassModifiers2() throws Exception {
+ CtClass cc = sloader.get("test5.InnerModifier2$Protected");
+ Class<?> ccc = Class.forName("test5.InnerModifier2$Protected");
+ assertEquals(cc.getModifiers(), ccc.getModifiers());
+ assertTrue(Modifier.isProtected(cc.getModifiers()));
+
+ cc = sloader.get("test5.InnerModifier2$Public");
+ ccc = Class.forName("test5.InnerModifier2$Public");
+ assertEquals(cc.getModifiers(), ccc.getModifiers());
+ assertTrue(Modifier.isPublic(cc.getModifiers()));
+
+ cc = sloader.get("test5.InnerModifier2$Private");
+ ccc = Class.forName("test5.InnerModifier2$Private");
+ assertEquals(cc.getModifiers(), ccc.getModifiers());
+ assertTrue(Modifier.isPrivate(cc.getModifiers()));
+
+ cc = sloader.get("test5.InnerModifier2$Package");
+ ccc = Class.forName("test5.InnerModifier2$Package");
+ assertEquals(cc.getModifiers(), ccc.getModifiers());
+ assertTrue(Modifier.isPackage(cc.getModifiers()));
+
+ cc = sloader.get("test5.InnerModifier2$ProtectedStatic");
+ ccc = Class.forName("test5.InnerModifier2$ProtectedStatic");
+ assertEquals(cc.getModifiers(), ccc.getModifiers());
+ assertTrue(Modifier.isProtected(cc.getModifiers()));
+ assertTrue(Modifier.isStatic(cc.getModifiers()));
+
+ cc = sloader.get("test5.InnerModifier2$PublicStatic");
+ ccc = Class.forName("test5.InnerModifier2$PublicStatic");
+ assertEquals(cc.getModifiers(), ccc.getModifiers());
+ assertTrue(Modifier.isPublic(cc.getModifiers()));
+ assertTrue(Modifier.isStatic(cc.getModifiers()));
+
+ cc = sloader.get("test5.InnerModifier2$PrivateStatic");
+ ccc = Class.forName("test5.InnerModifier2$PrivateStatic");
+ assertEquals(cc.getModifiers(), ccc.getModifiers());
+ assertTrue(Modifier.isPrivate(cc.getModifiers()));
+ assertTrue(Modifier.isStatic(cc.getModifiers()));
+
+ cc = sloader.get("test5.InnerModifier2$PackageStatic");
+ ccc = Class.forName("test5.InnerModifier2$PackageStatic");
+ assertEquals(cc.getModifiers(), ccc.getModifiers());
+ assertTrue(Modifier.isPackage(cc.getModifiers()));
+ assertTrue(Modifier.isStatic(cc.getModifiers()));
+ }
+
private InnerClassesAttribute getInnerClassAttr(CtClass cc) {
return (InnerClassesAttribute)cc.getClassFile2().getAttribute(InnerClassesAttribute.tag);
}
diff --git a/src/test/test/javassist/proxy/TestSecuredPrivileged.java b/src/test/test/javassist/proxy/TestSecuredPrivileged.java
new file mode 100644
index 00000000..c51555f5
--- /dev/null
+++ b/src/test/test/javassist/proxy/TestSecuredPrivileged.java
@@ -0,0 +1,281 @@
+package test.javassist.proxy;
+import static org.hamcrest.Matchers.arrayWithSize;
+import static org.hamcrest.Matchers.both;
+import static org.hamcrest.Matchers.endsWith;
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.instanceOf;
+import static org.hamcrest.Matchers.not;
+import static org.hamcrest.Matchers.notNullValue;
+import static org.hamcrest.Matchers.startsWith;
+import static org.hamcrest.Matchers.stringContainsInOrder;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.security.ProtectionDomain;
+import java.util.Arrays;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+import javassist.ClassPool;
+import javassist.CtClass;
+import javassist.util.proxy.DefineClassHelper;
+
+public class TestSecuredPrivileged {
+
+ public TestSecuredPrivileged() {
+ }
+
+ @Rule
+ public ExpectedException thrown = ExpectedException.none();
+ /**
+ * Test proves that you cannot even access members with
+ * private static and final modifiers. */
+ @Test
+ public void testDefinedHelperPrivilegedFieldVisibility() {
+ try {
+ Field privi = DefineClassHelper.class.getDeclaredField("privileged");
+ assertTrue(Modifier.isStatic(privi.getModifiers()));
+ thrown.expectCause(instanceOf(IllegalAccessException.class));
+ thrown.expectMessage(both(stringContainsInOrder(Arrays.asList("cannot access a member")))
+ .and(stringContainsInOrder(Arrays.asList("with modifiers \"private static final".split("", 1)))));
+
+ privi.get(null);
+ } catch(Throwable t) {
+ throw new RuntimeException(t);
+ }
+ }
+ /**
+ * Test proves that the default enum constant is a class and specifically
+ * auto selected for Java 9. */
+ @Test
+ public void testDefinedHelperPrivilegedField() {
+ try {
+ Field privi = DefineClassHelper.class.getDeclaredField("privileged");
+ assertTrue(Modifier.isStatic(privi.getModifiers()));
+ Constructor<DefineClassHelper> con = DefineClassHelper.class.getDeclaredConstructor();
+ con.setAccessible(true);
+ DefineClassHelper inst = con.newInstance();
+ assertThat(inst, instanceOf(DefineClassHelper.class));
+ privi.setAccessible(true);
+ Object p = privi.get(inst);
+ assertThat(""+p, equalTo("JAVA_9"));
+ assertThat(p.getClass().getName(), endsWith("SecuredPrivileged$1"));
+ } catch(Throwable t) {
+ throw new RuntimeException(t);
+ }
+ }
+ /**
+ * Test proves that caller class security is enforced and works
+ * as expected. */
+ @Test
+ public void testDefinedHelperPrivilegedFieldMethodAccessDenied() {
+ try {
+ Constructor<DefineClassHelper> con = DefineClassHelper.class.getDeclaredConstructor();
+ con.setAccessible(true);
+ DefineClassHelper inst = con.newInstance();
+ Field privi = DefineClassHelper.class.getDeclaredField("privileged");
+ privi.setAccessible(true);
+ Object priviInst = privi.get(inst);
+ Method defineClass = priviInst.getClass().getDeclaredMethod(
+ "defineClass", new Class[] {
+ String.class, byte[].class, int.class, int.class,
+ ClassLoader.class, ProtectionDomain.class
+ });
+
+ assertThat(defineClass, notNullValue());
+ defineClass.setAccessible(true);
+ assertThat(defineClass.getName(), equalTo("defineClass"));
+ assertTrue(defineClass.canAccess(priviInst));
+ ClassPool cp = ClassPool.getDefault();
+ CtClass c = cp.makeClass("a.b.C");
+ byte[] bc = c.toBytecode();
+
+ thrown.expectCause(instanceOf(IllegalAccessError.class));
+ thrown.expectMessage(equalTo("java.lang.IllegalAccessError: Access denied for caller."));
+
+ @SuppressWarnings("unused")
+ Object res = defineClass.invoke(priviInst, new Object[] {
+ c.getName(), bc, 0, bc.length, new ClassLoader() {},
+ ClassLoader.class.getProtectionDomain()
+ });
+ } catch(InvocationTargetException t) {
+ throw new RuntimeException(t.getTargetException());
+ } catch(Throwable t) { throw new RuntimeException(t); }
+ }
+ /**
+ * Test proves that we do have 3 enum constants in the private static
+ * inner class. */
+ @Test
+ public void testDefinedHelperEnumClass() {
+ try {
+ Constructor<DefineClassHelper> con = DefineClassHelper.class.getDeclaredConstructor();
+ con.setAccessible(true);
+ assertThat(DefineClassHelper.class.getDeclaredClasses(), arrayWithSize(1));
+ Class<?> secPriv = DefineClassHelper.class.getDeclaredClasses()[0];
+ assertTrue(secPriv.isEnum());
+ assertThat(secPriv.getEnumConstants(), arrayWithSize(3));
+ assertThat(""+secPriv.getEnumConstants()[0], equalTo("JAVA_9"));
+ assertThat(""+secPriv.getEnumConstants()[1], equalTo("JAVA_7"));
+ assertThat(""+secPriv.getEnumConstants()[2], equalTo("JAVA_OTHER"));
+
+ } catch (Throwable t) {t.printStackTrace();}
+
+ }
+ /**
+ * Test proves that you cannot modify private static final reference even
+ * with setAccessible(true). */
+ @Test
+ public void testDefinedHelperCannotSetPrivileged() {
+ try {
+ Constructor<DefineClassHelper> con = DefineClassHelper.class.getDeclaredConstructor();
+ con.setAccessible(true);
+ DefineClassHelper inst = con.newInstance();
+ Class<?> secPriv = DefineClassHelper.class.getDeclaredClasses()[0];
+ Object J7 = secPriv.getEnumConstants()[1];
+ Field privi = DefineClassHelper.class.getDeclaredField("privileged");
+ privi.setAccessible(true);
+ thrown.expectCause(instanceOf(IllegalAccessException.class));
+ thrown.expectMessage(startsWith("java.lang.IllegalAccessException: Can not set static final"));
+ privi.set(inst, J7);
+
+ } catch (Throwable t) {throw new RuntimeException(t);}
+
+ }
+ /**
+ * Test proves that you can achieve the impossible and modify private
+ * static final class reference without an instance. Now we can Mock
+ * test JDK 6 to 8 functionality */
+ @Test
+ public void testDefinedHelperSetPrivilegedToJava7() {
+ try {
+ Constructor<DefineClassHelper> con = DefineClassHelper.class.getDeclaredConstructor();
+ con.setAccessible(true);
+ DefineClassHelper inst = con.newInstance();
+ Class<?> secPriv = DefineClassHelper.class.getDeclaredClasses()[0];
+ Object J9 = secPriv.getEnumConstants()[0];
+ Object J7 = secPriv.getEnumConstants()[1];
+ Field privi = DefineClassHelper.class.getDeclaredField("privileged");
+ privi.setAccessible(true);
+ Object privInst = privi.get(inst);
+ Field unsf = privInst.getClass().getDeclaredField("sunMiscUnsafe");
+ unsf.setAccessible(true);
+ Object refu = unsf.get(privInst);
+ Field tuf = refu.getClass().getDeclaredField("sunMiscUnsafeTheUnsafe");
+ tuf.setAccessible(true);
+ Object tu = tuf.get(refu);
+ Method tu_call = tu.getClass().getMethod("call", new Class<?>[] {String.class, Object[].class});
+ tu_call.setAccessible(true);
+ long offset = (Long) tu_call.invoke(tu, new Object[] {"staticFieldOffset", new Object[] {privi}});
+ tu_call.invoke(tu, new Object[] {"putObjectVolatile", new Object[] {DefineClassHelper.class, offset, J7}});
+
+ Object p = privi.get(inst);
+ assertThat(""+p, equalTo("JAVA_7"));
+ assertThat(p.getClass().getName(), endsWith("SecuredPrivileged$2"));
+
+ tu_call.invoke(tu, new Object[] {"putObjectVolatile", new Object[] {DefineClassHelper.class, offset, J9}});
+
+ } catch (Throwable t) {t.printStackTrace();}
+
+ }
+ /**
+ * Test proves that Java 7+ MethodHandle defineClass (or DefineClassHelper.toClass)
+ * works as expected. */
+ @Test
+ public void testDefinedHelperJava7ToClass() {
+ try {
+ Constructor<DefineClassHelper> con = DefineClassHelper.class.getDeclaredConstructor();
+ con.setAccessible(true);
+ DefineClassHelper inst = con.newInstance();
+ Class<?> secPriv = DefineClassHelper.class.getDeclaredClasses()[0];
+ Object J9 = secPriv.getEnumConstants()[0];
+ Object J7 = secPriv.getEnumConstants()[1];
+ Field privi = DefineClassHelper.class.getDeclaredField("privileged");
+ privi.setAccessible(true);
+ Object privInst = privi.get(inst);
+ Field unsf = privInst.getClass().getDeclaredField("sunMiscUnsafe");
+ unsf.setAccessible(true);
+ Object refu = unsf.get(privInst);
+ Field tuf = refu.getClass().getDeclaredField("sunMiscUnsafeTheUnsafe");
+ tuf.setAccessible(true);
+ Object tu = tuf.get(refu);
+ Method tu_call = tu.getClass().getMethod("call", new Class<?>[] {String.class, Object[].class});
+ tu_call.setAccessible(true);
+ long offset = (Long) tu_call.invoke(tu, new Object[] {"staticFieldOffset", new Object[] {privi}});
+ tu_call.invoke(tu, new Object[] {"putObjectVolatile", new Object[] {DefineClassHelper.class, offset, J7}});
+
+ ClassPool cp = ClassPool.getDefault();
+ CtClass c = cp.makeClass("a.b.J7");
+ byte[] bc = c.toBytecode();
+ Class<?> bcCls = DefineClassHelper.toClass("a.b.J7", new ClassLoader() {}, null, bc);
+ assertThat(bcCls.getName(), equalTo("a.b.J7"));
+ assertThat(bcCls.getDeclaredConstructor().newInstance(),
+ not(equalTo(bcCls.getDeclaredConstructor().newInstance())));
+
+ tu_call.invoke(tu, new Object[] {"putObjectVolatile", new Object[] {DefineClassHelper.class, offset, J9}});
+
+ } catch (Throwable t) {t.printStackTrace();}
+
+ }
+ /**
+ * Test proves that Java 6 reflection method defineClass (or DefineClassHelper.toClass)
+ * works as expected. */
+ @Test
+ public void testDefinedHelperJavaOtherToClass() {
+ try {
+ Constructor<DefineClassHelper> con = DefineClassHelper.class.getDeclaredConstructor();
+ con.setAccessible(true);
+ DefineClassHelper inst = con.newInstance();
+ Class<?> secPriv = DefineClassHelper.class.getDeclaredClasses()[0];
+ Object J9 = secPriv.getEnumConstants()[0];
+ Object JO = secPriv.getEnumConstants()[2];
+ Field privi = DefineClassHelper.class.getDeclaredField("privileged");
+ privi.setAccessible(true);
+ Object privInst = privi.get(inst);
+ Field unsf = privInst.getClass().getDeclaredField("sunMiscUnsafe");
+ unsf.setAccessible(true);
+ Object refu = unsf.get(privInst);
+ Field tuf = refu.getClass().getDeclaredField("sunMiscUnsafeTheUnsafe");
+ tuf.setAccessible(true);
+ Object tu = tuf.get(refu);
+ Method tu_call = tu.getClass().getMethod("call", new Class<?>[] {String.class, Object[].class});
+ tu_call.setAccessible(true);
+ long offset = (Long) tu_call.invoke(tu, new Object[] {"staticFieldOffset", new Object[] {privi}});
+ tu_call.invoke(tu, new Object[] {"putObjectVolatile", new Object[] {DefineClassHelper.class, offset, JO}});
+
+ ClassPool cp = ClassPool.getDefault();
+ CtClass c = cp.makeClass("a.b.JO");
+ byte[] bc = c.toBytecode();
+ Class<?> bcCls = DefineClassHelper.toClass("a.b.JO", new ClassLoader() {}, null, bc);
+ assertThat(bcCls.getName(), equalTo("a.b.JO"));
+ assertThat(bcCls.getDeclaredConstructor().newInstance(),
+ not(equalTo(bcCls.getDeclaredConstructor().newInstance())));
+
+ tu_call.invoke(tu, new Object[] {"putObjectVolatile", new Object[] {DefineClassHelper.class, offset, J9}});
+
+ } catch (Throwable t) {t.printStackTrace();}
+
+ }
+ /**
+ * Test proves that default Java 9 defineClass (or DefineClassHelper.toClass)
+ * works as expected. */
+ @Test
+ public void testDefinedHelperDefaultToClass() {
+ try {
+ ClassPool cp = ClassPool.getDefault();
+ CtClass c = cp.makeClass("a.b.D");
+ byte[] bc = c.toBytecode();
+ Class<?> bcCls = DefineClassHelper.toClass("a.b.D", new ClassLoader() {}, null, bc);
+ assertThat(bcCls.getName(), equalTo("a.b.D"));
+ assertThat(bcCls.getDeclaredConstructor().newInstance(),
+ not(equalTo(bcCls.getDeclaredConstructor().newInstance())));
+ } catch (Throwable t) {t.printStackTrace();}
+
+ }
+}
diff --git a/src/test/test1/FieldInit.java b/src/test/test1/FieldInit.java
index 87f5a3bc..ee483149 100644
--- a/src/test/test1/FieldInit.java
+++ b/src/test/test1/FieldInit.java
@@ -14,4 +14,11 @@ public class FieldInit {
--loop;
} while (loop > 0);
}
+
+ public static class FI {
+ public FieldInit fi;
+ public FI(FieldInit fi) {
+ this.fi = fi;
+ }
+ }
}
diff --git a/src/test/test5/InnerModifier2.java b/src/test/test5/InnerModifier2.java
new file mode 100644
index 00000000..009a0321
--- /dev/null
+++ b/src/test/test5/InnerModifier2.java
@@ -0,0 +1,13 @@
+package test5;
+
+@SuppressWarnings("unused")
+public class InnerModifier2 {
+ public class Public {}
+ protected class Protected {}
+ private class Private {}
+ class Package {}
+ public static class PublicStatic {}
+ protected static class ProtectedStatic {}
+ private static class PrivateStatic {}
+ static class PackageStatic {}
+}