8058575: IllegalAccessError trying to access package-private class from VM anonymous class
Put anonymous classes in unnamed package into host class's package. Throw exception if host class's package differs from anonymous class. Reviewed-by: coleenp, acorn
This commit is contained in:
parent
c271d83599
commit
e8e6415b7a
@ -5407,6 +5407,59 @@ void ClassFileParser::fill_instance_klass(InstanceKlass* ik, bool changed_by_loa
|
||||
debug_only(ik->verify();)
|
||||
}
|
||||
|
||||
// For an anonymous class that is in the unnamed package, move it to its host class's
|
||||
// package by prepending its host class's package name to its class name and setting
|
||||
// its _class_name field.
|
||||
void ClassFileParser::prepend_host_package_name(const InstanceKlass* host_klass, TRAPS) {
|
||||
ResourceMark rm(THREAD);
|
||||
assert(strrchr(_class_name->as_C_string(), '/') == NULL,
|
||||
"Anonymous class should not be in a package");
|
||||
const char* host_pkg_name =
|
||||
ClassLoader::package_from_name(host_klass->name()->as_C_string(), NULL);
|
||||
|
||||
if (host_pkg_name != NULL) {
|
||||
size_t host_pkg_len = strlen(host_pkg_name);
|
||||
int class_name_len = _class_name->utf8_length();
|
||||
char* new_anon_name =
|
||||
NEW_RESOURCE_ARRAY(char, host_pkg_len + 1 + class_name_len);
|
||||
// Copy host package name and trailing /.
|
||||
strncpy(new_anon_name, host_pkg_name, host_pkg_len);
|
||||
new_anon_name[host_pkg_len] = '/';
|
||||
// Append anonymous class name. The anonymous class name can contain odd
|
||||
// characters. So, do a strncpy instead of using sprintf("%s...").
|
||||
strncpy(new_anon_name + host_pkg_len + 1, (char *)_class_name->base(), class_name_len);
|
||||
|
||||
// Create a symbol and update the anonymous class name.
|
||||
_class_name = SymbolTable::new_symbol(new_anon_name,
|
||||
(int)host_pkg_len + 1 + class_name_len,
|
||||
CHECK);
|
||||
}
|
||||
}
|
||||
|
||||
// If the host class and the anonymous class are in the same package then do
|
||||
// nothing. If the anonymous class is in the unnamed package then move it to its
|
||||
// host's package. If the classes are in different packages then throw an IAE
|
||||
// exception.
|
||||
void ClassFileParser::fix_anonymous_class_name(TRAPS) {
|
||||
assert(_host_klass != NULL, "Expected an anonymous class");
|
||||
|
||||
const jbyte* anon_last_slash = UTF8::strrchr(_class_name->base(),
|
||||
_class_name->utf8_length(), '/');
|
||||
if (anon_last_slash == NULL) { // Unnamed package
|
||||
prepend_host_package_name(_host_klass, CHECK);
|
||||
} else {
|
||||
if (!InstanceKlass::is_same_class_package(_host_klass->class_loader(),
|
||||
_host_klass->name(),
|
||||
_host_klass->class_loader(),
|
||||
_class_name)) {
|
||||
ResourceMark rm(THREAD);
|
||||
THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
|
||||
err_msg("Host class %s and anonymous class %s are in different packages",
|
||||
_host_klass->name()->as_C_string(), _class_name->as_C_string()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool relax_format_check_for(ClassLoaderData* loader_data) {
|
||||
bool trusted = (loader_data->is_the_null_class_loader_data() ||
|
||||
SystemDictionary::is_platform_class_loader(loader_data->class_loader()));
|
||||
@ -5422,7 +5475,7 @@ ClassFileParser::ClassFileParser(ClassFileStream* stream,
|
||||
Symbol* name,
|
||||
ClassLoaderData* loader_data,
|
||||
Handle protection_domain,
|
||||
const Klass* host_klass,
|
||||
const InstanceKlass* host_klass,
|
||||
GrowableArray<Handle>* cp_patches,
|
||||
Publicity pub_level,
|
||||
TRAPS) :
|
||||
@ -5697,6 +5750,13 @@ void ClassFileParser::parse_stream(const ClassFileStream* const stream,
|
||||
return;
|
||||
}
|
||||
|
||||
// if this is an anonymous class fix up its name if it's in the unnamed
|
||||
// package. Otherwise, throw IAE if it is in a different package than
|
||||
// its host class.
|
||||
if (_host_klass != NULL) {
|
||||
fix_anonymous_class_name(CHECK);
|
||||
}
|
||||
|
||||
// Verification prevents us from creating names with dots in them, this
|
||||
// asserts that that's the case.
|
||||
assert(is_internal_format(_class_name), "external class name format used internally");
|
||||
|
@ -79,7 +79,7 @@ class ClassFileParser VALUE_OBJ_CLASS_SPEC {
|
||||
const Symbol* _requested_name;
|
||||
Symbol* _class_name;
|
||||
mutable ClassLoaderData* _loader_data;
|
||||
const Klass* _host_klass;
|
||||
const InstanceKlass* _host_klass;
|
||||
GrowableArray<Handle>* _cp_patches; // overrides for CP entries
|
||||
|
||||
// Metadata created before the instance klass is created. Must be deallocated
|
||||
@ -155,6 +155,9 @@ class ClassFileParser VALUE_OBJ_CLASS_SPEC {
|
||||
ConstantPool* cp,
|
||||
TRAPS);
|
||||
|
||||
void prepend_host_package_name(const InstanceKlass* host_klass, TRAPS);
|
||||
void fix_anonymous_class_name(TRAPS);
|
||||
|
||||
void fill_instance_klass(InstanceKlass* ik, bool cf_changed_in_CFLH, TRAPS);
|
||||
void set_klass(InstanceKlass* instance);
|
||||
|
||||
@ -474,7 +477,7 @@ class ClassFileParser VALUE_OBJ_CLASS_SPEC {
|
||||
Symbol* name,
|
||||
ClassLoaderData* loader_data,
|
||||
Handle protection_domain,
|
||||
const Klass* host_klass,
|
||||
const InstanceKlass* host_klass,
|
||||
GrowableArray<Handle>* cp_patches,
|
||||
Publicity pub_level,
|
||||
TRAPS);
|
||||
@ -500,7 +503,7 @@ class ClassFileParser VALUE_OBJ_CLASS_SPEC {
|
||||
bool is_anonymous() const { return _host_klass != NULL; }
|
||||
bool is_interface() const { return _access_flags.is_interface(); }
|
||||
|
||||
const Klass* host_klass() const { return _host_klass; }
|
||||
const InstanceKlass* host_klass() const { return _host_klass; }
|
||||
const GrowableArray<Handle>* cp_patches() const { return _cp_patches; }
|
||||
ClassLoaderData* loader_data() const { return _loader_data; }
|
||||
const Symbol* class_name() const { return _class_name; }
|
||||
|
@ -94,7 +94,7 @@ instanceKlassHandle KlassFactory::create_from_stream(ClassFileStream* stream,
|
||||
Symbol* name,
|
||||
ClassLoaderData* loader_data,
|
||||
Handle protection_domain,
|
||||
const Klass* host_klass,
|
||||
const InstanceKlass* host_klass,
|
||||
GrowableArray<Handle>* cp_patches,
|
||||
TRAPS) {
|
||||
|
||||
|
@ -72,7 +72,7 @@ class KlassFactory : AllStatic {
|
||||
Symbol* name,
|
||||
ClassLoaderData* loader_data,
|
||||
Handle protection_domain,
|
||||
const Klass* host_klass,
|
||||
const InstanceKlass* host_klass,
|
||||
GrowableArray<Handle>* cp_patches,
|
||||
TRAPS);
|
||||
};
|
||||
|
@ -1027,7 +1027,7 @@ Klass* SystemDictionary::parse_stream(Symbol* class_name,
|
||||
Handle class_loader,
|
||||
Handle protection_domain,
|
||||
ClassFileStream* st,
|
||||
const Klass* host_klass,
|
||||
const InstanceKlass* host_klass,
|
||||
GrowableArray<Handle>* cp_patches,
|
||||
TRAPS) {
|
||||
|
||||
|
@ -299,7 +299,7 @@ public:
|
||||
Handle class_loader,
|
||||
Handle protection_domain,
|
||||
ClassFileStream* st,
|
||||
const Klass* host_klass,
|
||||
const InstanceKlass* host_klass,
|
||||
GrowableArray<Handle>* cp_patches,
|
||||
TRAPS);
|
||||
|
||||
|
@ -2786,7 +2786,7 @@ void ClassVerifier::verify_invoke_instructions(
|
||||
// direct interface relative to the host class
|
||||
have_imr_indirect = (have_imr_indirect &&
|
||||
!is_same_or_direct_interface(
|
||||
InstanceKlass::cast(current_class()->host_klass()),
|
||||
current_class()->host_klass(),
|
||||
host_klass_type, ref_class_type));
|
||||
}
|
||||
if (!subtype) {
|
||||
|
@ -619,8 +619,8 @@ class InstanceKlass: public Klass {
|
||||
objArrayOop signers() const;
|
||||
|
||||
// host class
|
||||
Klass* host_klass() const {
|
||||
Klass** hk = (Klass**)adr_host_klass();
|
||||
InstanceKlass* host_klass() const {
|
||||
InstanceKlass** hk = adr_host_klass();
|
||||
if (hk == NULL) {
|
||||
return NULL;
|
||||
} else {
|
||||
@ -628,9 +628,9 @@ class InstanceKlass: public Klass {
|
||||
return *hk;
|
||||
}
|
||||
}
|
||||
void set_host_klass(const Klass* host) {
|
||||
void set_host_klass(const InstanceKlass* host) {
|
||||
assert(is_anonymous(), "not anonymous");
|
||||
const Klass** addr = (const Klass**)adr_host_klass();
|
||||
const InstanceKlass** addr = (const InstanceKlass **)adr_host_klass();
|
||||
assert(addr != NULL, "no reversed space");
|
||||
if (addr != NULL) {
|
||||
*addr = host;
|
||||
@ -1057,13 +1057,13 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
Klass** adr_host_klass() const {
|
||||
InstanceKlass** adr_host_klass() const {
|
||||
if (is_anonymous()) {
|
||||
Klass** adr_impl = adr_implementor();
|
||||
InstanceKlass** adr_impl = (InstanceKlass **)adr_implementor();
|
||||
if (adr_impl != NULL) {
|
||||
return adr_impl + 1;
|
||||
} else {
|
||||
return end_of_nonstatic_oop_maps();
|
||||
return (InstanceKlass **)end_of_nonstatic_oop_maps();
|
||||
}
|
||||
} else {
|
||||
return NULL;
|
||||
|
@ -783,6 +783,7 @@ UNSAFE_ENTRY(jclass, Unsafe_DefineClass0(JNIEnv *env, jobject unsafe, jstring na
|
||||
|
||||
// define a class but do not make it known to the class loader or system dictionary
|
||||
// - host_class: supplies context for linkage, access control, protection domain, and class loader
|
||||
// if host_class is itself anonymous then it is replaced with its host class.
|
||||
// - data: bytes of a class file, a raw memory address (length gives the number of bytes)
|
||||
// - cp_patches: where non-null entries exist, they replace corresponding CP entries in data
|
||||
|
||||
@ -791,8 +792,12 @@ UNSAFE_ENTRY(jclass, Unsafe_DefineClass0(JNIEnv *env, jobject unsafe, jstring na
|
||||
// link to any member of U. Just after U is loaded, the only way to use it is reflectively,
|
||||
// through java.lang.Class methods like Class.newInstance.
|
||||
|
||||
// The package of an anonymous class must either match its host's class's package or be in the
|
||||
// unnamed package. If it is in the unnamed package then it will be put in its host class's
|
||||
// package.
|
||||
//
|
||||
|
||||
// Access checks for linkage sites within U continue to follow the same rules as for named classes.
|
||||
// The package of an anonymous class is given by the package qualifier on the name under which it was loaded.
|
||||
// An anonymous class also has special privileges to access any member of its host class.
|
||||
// This is the main reason why this loading operation is unsafe. The purpose of this is to
|
||||
// allow language implementations to simulate "open classes"; a host class in effect gets
|
||||
@ -874,9 +879,11 @@ Unsafe_DefineAnonymousClass_impl(JNIEnv *env,
|
||||
|
||||
// Primitive types have NULL Klass* fields in their java.lang.Class instances.
|
||||
if (host_klass == NULL) {
|
||||
THROW_0(vmSymbols::java_lang_IllegalArgumentException());
|
||||
THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "Host class is null");
|
||||
}
|
||||
|
||||
assert(host_klass->is_instance_klass(), "Host class must be an instance class");
|
||||
|
||||
const char* host_source = host_klass->external_name();
|
||||
Handle host_loader(THREAD, host_klass->class_loader());
|
||||
Handle host_domain(THREAD, host_klass->protection_domain());
|
||||
@ -907,7 +914,7 @@ Unsafe_DefineAnonymousClass_impl(JNIEnv *env,
|
||||
host_loader,
|
||||
host_domain,
|
||||
&st,
|
||||
host_klass,
|
||||
InstanceKlass::cast(host_klass),
|
||||
cp_patches,
|
||||
CHECK_NULL);
|
||||
if (anonk == NULL) {
|
||||
|
@ -412,13 +412,13 @@ oop Reflection::array_component_type(oop mirror, TRAPS) {
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool under_host_klass(const InstanceKlass* ik, const Klass* host_klass) {
|
||||
static bool under_host_klass(const InstanceKlass* ik, const InstanceKlass* host_klass) {
|
||||
DEBUG_ONLY(int inf_loop_check = 1000 * 1000 * 1000);
|
||||
for (;;) {
|
||||
const Klass* hc = (const Klass*)ik->host_klass();
|
||||
const InstanceKlass* hc = ik->host_klass();
|
||||
if (hc == NULL) return false;
|
||||
if (hc == host_klass) return true;
|
||||
ik = InstanceKlass::cast(hc);
|
||||
ik = hc;
|
||||
|
||||
// There's no way to make a host class loop short of patching memory.
|
||||
// Therefore there cannot be a loop here unless there's another bug.
|
||||
@ -436,8 +436,8 @@ static bool can_relax_access_check_for(const Klass* accessor,
|
||||
|
||||
// If either is on the other's host_klass chain, access is OK,
|
||||
// because one is inside the other.
|
||||
if (under_host_klass(accessor_ik, accessee) ||
|
||||
under_host_klass(accessee_ik, accessor))
|
||||
if (under_host_klass(accessor_ik, accessee_ik) ||
|
||||
under_host_klass(accessee_ik, accessor_ik))
|
||||
return true;
|
||||
|
||||
if ((RelaxAccessControlCheck &&
|
||||
|
@ -62,7 +62,7 @@ import static jdk.internal.org.objectweb.asm.Opcodes.IRETURN;
|
||||
public class CallSiteDepContextTest {
|
||||
static final Unsafe UNSAFE = Unsafe.getUnsafe();
|
||||
static final MethodHandles.Lookup LOOKUP = MethodHandleHelper.IMPL_LOOKUP;
|
||||
static final String CLASS_NAME = "java/lang/invoke/Test";
|
||||
static final String CLASS_NAME = "compiler/jsr292/Test";
|
||||
static final String METHOD_NAME = "m";
|
||||
static final MethodType TYPE = MethodType.methodType(int.class);
|
||||
|
||||
@ -129,8 +129,8 @@ public class CallSiteDepContextTest {
|
||||
}
|
||||
|
||||
public static void testSharedCallSite() throws Throwable {
|
||||
Class<?> cls1 = UNSAFE.defineAnonymousClass(Object.class, getClassFile("CS_1"), null);
|
||||
Class<?> cls2 = UNSAFE.defineAnonymousClass(Object.class, getClassFile("CS_2"), null);
|
||||
Class<?> cls1 = UNSAFE.defineAnonymousClass(CallSiteDepContextTest.class, getClassFile("CS_1"), null);
|
||||
Class<?> cls2 = UNSAFE.defineAnonymousClass(CallSiteDepContextTest.class, getClassFile("CS_2"), null);
|
||||
|
||||
MethodHandle[] mhs = new MethodHandle[] {
|
||||
LOOKUP.findStatic(cls1, METHOD_NAME, TYPE),
|
||||
@ -151,7 +151,7 @@ public class CallSiteDepContextTest {
|
||||
execute(1, mh);
|
||||
|
||||
// mcs.context == cls1
|
||||
Class<?> cls1 = UNSAFE.defineAnonymousClass(Object.class, getClassFile("NonBound_1"), null);
|
||||
Class<?> cls1 = UNSAFE.defineAnonymousClass(CallSiteDepContextTest.class, getClassFile("NonBound_1"), null);
|
||||
MethodHandle mh1 = LOOKUP.findStatic(cls1, METHOD_NAME, TYPE);
|
||||
|
||||
execute(1, mh1);
|
||||
@ -170,8 +170,8 @@ public class CallSiteDepContextTest {
|
||||
mcs = new MutableCallSite(LOOKUP.findStatic(T.class, "f1", TYPE));
|
||||
|
||||
Class<?>[] cls = new Class[] {
|
||||
UNSAFE.defineAnonymousClass(Object.class, getClassFile("GC_1" + id), null),
|
||||
UNSAFE.defineAnonymousClass(Object.class, getClassFile("GC_2" + id), null),
|
||||
UNSAFE.defineAnonymousClass(CallSiteDepContextTest.class, getClassFile("GC_1" + id), null),
|
||||
UNSAFE.defineAnonymousClass(CallSiteDepContextTest.class, getClassFile("GC_2" + id), null),
|
||||
};
|
||||
|
||||
MethodHandle[] mhs = new MethodHandle[] {
|
||||
@ -185,7 +185,7 @@ public class CallSiteDepContextTest {
|
||||
execute(1, mhs);
|
||||
|
||||
ref = new PhantomReference<>(cls[0], rq);
|
||||
cls[0] = UNSAFE.defineAnonymousClass(Object.class, getClassFile("GC_3" + id), null);
|
||||
cls[0] = UNSAFE.defineAnonymousClass(CallSiteDepContextTest.class, getClassFile("GC_3" + id), null);
|
||||
mhs[0] = LOOKUP.findStatic(cls[0], METHOD_NAME, TYPE);
|
||||
|
||||
do {
|
||||
|
134
hotspot/test/runtime/defineAnonClass/DefineAnon.java
Normal file
134
hotspot/test/runtime/defineAnonClass/DefineAnon.java
Normal file
@ -0,0 +1,134 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test DefineAnon
|
||||
* @bug 8058575
|
||||
* @library /testlibrary
|
||||
* @modules java.base/jdk.internal.org.objectweb.asm
|
||||
* java.management
|
||||
* @compile -XDignore.symbol.file=true DefineAnon.java
|
||||
* @run main/othervm p1.DefineAnon
|
||||
*/
|
||||
|
||||
package p1;
|
||||
|
||||
import jdk.internal.org.objectweb.asm.ClassWriter;
|
||||
import jdk.internal.org.objectweb.asm.MethodVisitor;
|
||||
import jdk.internal.org.objectweb.asm.Opcodes;
|
||||
import sun.misc.Unsafe;
|
||||
|
||||
|
||||
class T {
|
||||
static protected void test0() { System.out.println("test0 (public)"); }
|
||||
static protected void test1() { System.out.println("test1 (protected)"); }
|
||||
static /*package-private*/ void test2() { System.out.println("test2 (package)"); }
|
||||
static private void test3() { System.out.println("test3 (private)"); }
|
||||
}
|
||||
|
||||
public class DefineAnon {
|
||||
|
||||
private static Unsafe getUnsafe() {
|
||||
try {
|
||||
java.lang.reflect.Field singleoneInstanceField = Unsafe.class.getDeclaredField("theUnsafe");
|
||||
singleoneInstanceField.setAccessible(true);
|
||||
return (Unsafe) singleoneInstanceField.get(null);
|
||||
} catch (Throwable ex) {
|
||||
throw new RuntimeException("Was unable to get Unsafe instance.");
|
||||
}
|
||||
}
|
||||
|
||||
static Unsafe UNSAFE = DefineAnon.getUnsafe();
|
||||
|
||||
static Class<?> getAnonClass(Class<?> hostClass, final String className) {
|
||||
final String superName = "java/lang/Object";
|
||||
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS + ClassWriter.COMPUTE_FRAMES);
|
||||
cw.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC + Opcodes.ACC_FINAL + Opcodes.ACC_SUPER, className, null, superName, null);
|
||||
|
||||
MethodVisitor mv = cw.visitMethod(Opcodes.ACC_STATIC | Opcodes.ACC_PUBLIC, "test", "()V", null, null);
|
||||
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "p1/T", "test0", "()V", false);
|
||||
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "p1/T", "test1", "()V", false);
|
||||
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "p1/T", "test2", "()V", false);
|
||||
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "p1/T", "test3", "()V", false);
|
||||
mv.visitInsn(Opcodes.RETURN);
|
||||
mv.visitMaxs(0, 0);
|
||||
mv.visitEnd();
|
||||
|
||||
final byte[] classBytes = cw.toByteArray();
|
||||
Class<?> invokerClass = UNSAFE.defineAnonymousClass(hostClass, classBytes, new Object[0]);
|
||||
UNSAFE.ensureClassInitialized(invokerClass);
|
||||
return invokerClass;
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Throwable {
|
||||
Throwable fail = null;
|
||||
|
||||
// Anonymous class has the privileges of its host class, so test[0123] should all work.
|
||||
System.out.println("Injecting from the same package (p1):");
|
||||
Class<?> p1cls = getAnonClass(T.class, "p1/AnonClass");
|
||||
try {
|
||||
p1cls.getMethod("test").invoke(null);
|
||||
} catch (Throwable ex) {
|
||||
ex.printStackTrace();
|
||||
fail = ex; // throw this to make test fail, since subtest failed
|
||||
}
|
||||
|
||||
// Anonymous class has different package name from host class. Should throw
|
||||
// IllegalArgumentException.
|
||||
System.out.println("Injecting from the wrong package (p2):");
|
||||
try {
|
||||
Class<?> p2cls = getAnonClass(DefineAnon.class, "p2/AnonClass");
|
||||
p2cls.getMethod("test").invoke(null);
|
||||
System.out.println("Failed, did not get expected IllegalArgumentException");
|
||||
} catch (java.lang.IllegalArgumentException e) {
|
||||
if (e.getMessage().contains("Host class p1/DefineAnon and anonymous class p2/AnonClass")) {
|
||||
System.out.println("Got expected IllegalArgumentException: " + e.getMessage());
|
||||
} else {
|
||||
throw new RuntimeException("Unexpected message: " + e.getMessage());
|
||||
}
|
||||
} catch (Throwable ex) {
|
||||
ex.printStackTrace();
|
||||
fail = ex; // throw this to make test fail, since subtest failed
|
||||
}
|
||||
|
||||
// Inject a class in the unnamed package into p1.T. It should be able
|
||||
// to access all methods in p1.T.
|
||||
System.out.println("Injecting unnamed package into correct host class:");
|
||||
try {
|
||||
Class<?> p3cls = getAnonClass(T.class, "AnonClass");
|
||||
p3cls.getMethod("test").invoke(null);
|
||||
} catch (Throwable ex) {
|
||||
ex.printStackTrace();
|
||||
fail = ex; // throw this to make test fail, since subtest failed
|
||||
}
|
||||
|
||||
// Try using an array class as the host class. This should throw IllegalArgumentException.
|
||||
try {
|
||||
Class<?> p3cls = getAnonClass(String[].class, "AnonClass");
|
||||
throw new RuntimeException("Expected IllegalArgumentException not thrown");
|
||||
} catch (IllegalArgumentException ex) {
|
||||
}
|
||||
|
||||
if (fail != null) throw fail; // make test fail, since subtest failed
|
||||
}
|
||||
}
|
91
hotspot/test/runtime/defineAnonClass/NestedUnsafe.java
Normal file
91
hotspot/test/runtime/defineAnonClass/NestedUnsafe.java
Normal file
@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8058575
|
||||
* @summary Creates an anonymous class inside of an anonymous class.
|
||||
* @library /test/lib
|
||||
* @modules java.base/jdk.internal.misc
|
||||
* java.compiler
|
||||
* java.management
|
||||
* @run main p.NestedUnsafe
|
||||
*/
|
||||
|
||||
package p;
|
||||
|
||||
import java.security.ProtectionDomain;
|
||||
import java.io.InputStream;
|
||||
import java.lang.*;
|
||||
import jdk.test.lib.*;
|
||||
import jdk.internal.misc.Unsafe;
|
||||
import jdk.test.lib.unsafe.UnsafeHelper;
|
||||
|
||||
|
||||
// Test that an anonymous class in package 'p' cannot define its own anonymous class
|
||||
// in another package.
|
||||
public class NestedUnsafe {
|
||||
// The String concatenation should create the nested anonymous class.
|
||||
static byte klassbuf[] = InMemoryJavaCompiler.compile("q.TestClass",
|
||||
"package q; " +
|
||||
"public class TestClass { " +
|
||||
" public static void concat(String one, String two) throws Throwable { " +
|
||||
" System.out.println(one + two);" +
|
||||
" } } ");
|
||||
|
||||
public static void main(String args[]) throws Exception {
|
||||
Unsafe unsafe = UnsafeHelper.getUnsafe();
|
||||
|
||||
// The anonymous class calls defineAnonymousClass creating a nested anonymous class.
|
||||
byte klassbuf2[] = InMemoryJavaCompiler.compile("p.TestClass2",
|
||||
"package p; " +
|
||||
"import jdk.internal.misc.Unsafe; " +
|
||||
"public class TestClass2 { " +
|
||||
" public static void doit() throws Throwable { " +
|
||||
" Unsafe unsafe = jdk.internal.misc.Unsafe.getUnsafe(); " +
|
||||
" Class klass2 = unsafe.defineAnonymousClass(TestClass2.class, p.NestedUnsafe.klassbuf, new Object[0]); " +
|
||||
" unsafe.ensureClassInitialized(klass2); " +
|
||||
" Class[] dArgs = new Class[2]; " +
|
||||
" dArgs[0] = String.class; " +
|
||||
" dArgs[1] = String.class; " +
|
||||
" try { " +
|
||||
" klass2.getMethod(\"concat\", dArgs).invoke(null, \"CC\", \"DD\"); " +
|
||||
" } catch (Throwable ex) { " +
|
||||
" throw new RuntimeException(\"Exception: \" + ex.toString()); " +
|
||||
" } " +
|
||||
"} } ",
|
||||
"--add-exports=java.base/jdk.internal.misc=ALL-UNNAMED");
|
||||
|
||||
Class klass2 = unsafe.defineAnonymousClass(p.NestedUnsafe.class, klassbuf2, new Object[0]);
|
||||
try {
|
||||
klass2.getMethod("doit").invoke(null);
|
||||
throw new RuntimeException("Expected exception not thrown");
|
||||
} catch (Throwable ex) {
|
||||
Throwable iae = ex.getCause();
|
||||
if (!iae.toString().contains(
|
||||
"IllegalArgumentException: Host class p/NestedUnsafe and anonymous class q/TestClass")) {
|
||||
throw new RuntimeException("Exception: " + iae.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
90
hotspot/test/runtime/defineAnonClass/NestedUnsafe2.java
Normal file
90
hotspot/test/runtime/defineAnonClass/NestedUnsafe2.java
Normal file
@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8058575
|
||||
* @summary Creates an anonymous class inside of an anonymous class.
|
||||
* @library /test/lib
|
||||
* @modules java.base/jdk.internal.misc
|
||||
* java.compiler
|
||||
* java.management
|
||||
* @run main p.NestedUnsafe2
|
||||
*/
|
||||
|
||||
package p;
|
||||
|
||||
import java.security.ProtectionDomain;
|
||||
import java.io.InputStream;
|
||||
import java.lang.*;
|
||||
import jdk.test.lib.*;
|
||||
import jdk.internal.misc.Unsafe;
|
||||
import jdk.test.lib.unsafe.UnsafeHelper;
|
||||
|
||||
|
||||
// Test that an anonymous class that gets put in its host's package cannot define
|
||||
// an anonymous class in another package.
|
||||
public class NestedUnsafe2 {
|
||||
// The String concatenation should create the nested anonymous class.
|
||||
public static byte klassbuf[] = InMemoryJavaCompiler.compile("q.TestClass",
|
||||
"package q; " +
|
||||
"public class TestClass { " +
|
||||
" public static void concat(String one, String two) throws Throwable { " +
|
||||
" System.out.println(one + two);" +
|
||||
" } } ");
|
||||
|
||||
public static void main(String args[]) throws Exception {
|
||||
Unsafe unsafe = UnsafeHelper.getUnsafe();
|
||||
|
||||
// The anonymous class calls defineAnonymousClass creating a nested anonymous class.
|
||||
byte klassbuf2[] = InMemoryJavaCompiler.compile("TestClass2",
|
||||
"import jdk.internal.misc.Unsafe; " +
|
||||
"public class TestClass2 { " +
|
||||
" public static void doit() throws Throwable { " +
|
||||
" Unsafe unsafe = jdk.internal.misc.Unsafe.getUnsafe(); " +
|
||||
" Class klass2 = unsafe.defineAnonymousClass(TestClass2.class, p.NestedUnsafe2.klassbuf, new Object[0]); " +
|
||||
" unsafe.ensureClassInitialized(klass2); " +
|
||||
" Class[] dArgs = new Class[2]; " +
|
||||
" dArgs[0] = String.class; " +
|
||||
" dArgs[1] = String.class; " +
|
||||
" try { " +
|
||||
" klass2.getMethod(\"concat\", dArgs).invoke(null, \"CC\", \"DD\"); " +
|
||||
" } catch (Throwable ex) { " +
|
||||
" throw new RuntimeException(\"Exception: \" + ex.toString()); " +
|
||||
" } " +
|
||||
"} } ",
|
||||
"--add-exports=java.base/jdk.internal.misc=ALL-UNNAMED");
|
||||
|
||||
Class klass2 = unsafe.defineAnonymousClass(p.NestedUnsafe2.class, klassbuf2, new Object[0]);
|
||||
try {
|
||||
klass2.getMethod("doit").invoke(null);
|
||||
throw new RuntimeException("Expected exception not thrown");
|
||||
} catch (Throwable ex) {
|
||||
Throwable iae = ex.getCause();
|
||||
if (!iae.toString().contains(
|
||||
"IllegalArgumentException: Host class p/NestedUnsafe2 and anonymous class q/TestClass")) {
|
||||
throw new RuntimeException("Exception: " + iae.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user