Merge
This commit is contained in:
commit
6b6510c34f
hotspot
src/share/vm/prims
test/runtime/RedefineTests
@ -7152,15 +7152,19 @@ class C2 extends C1 implements I2 {
|
|||||||
returns <code>JNI_FALSE</code>) the class can be neither
|
returns <code>JNI_FALSE</code>) the class can be neither
|
||||||
redefined nor retransformed.
|
redefined nor retransformed.
|
||||||
<p/>
|
<p/>
|
||||||
Primitive classes (for example, <code>java.lang.Integer.TYPE</code>)
|
Primitive classes (for example, <code>java.lang.Integer.TYPE</code>),
|
||||||
and array classes are never modifiable.
|
array classes, and some implementation defined classes are never modifiable.
|
||||||
<p/>
|
<p/>
|
||||||
</description>
|
</description>
|
||||||
<origin>new</origin>
|
<origin>new</origin>
|
||||||
<capabilities>
|
<capabilities>
|
||||||
<capability id="can_redefine_any_class">
|
<capability id="can_redefine_any_class">
|
||||||
If possessed then all classes (except primitive and array classes)
|
If possessed then all classes (except primitive, array, and some implementation defined
|
||||||
are modifiable.
|
classes) are modifiable (redefine or retransform).
|
||||||
|
</capability>
|
||||||
|
<capability id="can_retransform_any_class">
|
||||||
|
If possessed then all classes (except primitive, array, and some implementation defined
|
||||||
|
classes) are modifiable with <functionlink id="RetransformClasses"/>.
|
||||||
</capability>
|
</capability>
|
||||||
<capability id="can_redefine_classes">
|
<capability id="can_redefine_classes">
|
||||||
No effect on the result of the function.
|
No effect on the result of the function.
|
||||||
@ -9900,7 +9904,7 @@ myInit() {
|
|||||||
</capabilityfield>
|
</capabilityfield>
|
||||||
<capabilityfield id="can_redefine_any_class">
|
<capabilityfield id="can_redefine_any_class">
|
||||||
<description>
|
<description>
|
||||||
Can modify (retransform or redefine) any non-primitive non-array class.
|
Can modify (retransform or redefine) any modifiable class.
|
||||||
See <functionlink id="IsModifiableClass"/>.
|
See <functionlink id="IsModifiableClass"/>.
|
||||||
</description>
|
</description>
|
||||||
</capabilityfield>
|
</capabilityfield>
|
||||||
@ -10024,7 +10028,8 @@ myInit() {
|
|||||||
</capabilityfield>
|
</capabilityfield>
|
||||||
<capabilityfield id="can_retransform_any_class" since="1.1">
|
<capabilityfield id="can_retransform_any_class" since="1.1">
|
||||||
<description>
|
<description>
|
||||||
<functionlink id="RetransformClasses"/> can be called on any class
|
<functionlink id="RetransformClasses"/> can be called on any modifiable class.
|
||||||
|
See <functionlink id="IsModifiableClass"/>.
|
||||||
(<fieldlink id="can_retransform_classes" struct="jvmtiCapabilities"/>
|
(<fieldlink id="can_retransform_classes" struct="jvmtiCapabilities"/>
|
||||||
must also be set)
|
must also be set)
|
||||||
</description>
|
</description>
|
||||||
@ -12494,8 +12499,8 @@ myInit() {
|
|||||||
Otherwise, this event may be sent before the VM is initialized (the start
|
Otherwise, this event may be sent before the VM is initialized (the start
|
||||||
<functionlink id="GetPhase">phase</functionlink>).
|
<functionlink id="GetPhase">phase</functionlink>).
|
||||||
Some classes might not be compatible
|
Some classes might not be compatible
|
||||||
with the function (eg. ROMized classes) and this event will not be
|
with the function (eg. ROMized classes or implementation defined classes) and this event will
|
||||||
generated for these classes.
|
not be generated for these classes.
|
||||||
<p/>
|
<p/>
|
||||||
The agent must allocate the space for the modified
|
The agent must allocate the space for the modified
|
||||||
class file data buffer
|
class file data buffer
|
||||||
@ -14498,6 +14503,10 @@ typedef void (JNICALL *jvmtiEventVMInit)
|
|||||||
- Add new capability can_generate_early_class_hook_events
|
- Add new capability can_generate_early_class_hook_events
|
||||||
- Add new function GetNamedModule
|
- Add new function GetNamedModule
|
||||||
</change>
|
</change>
|
||||||
|
<change date="16 August 2016" version="9.0.0">
|
||||||
|
Clarified can_redefine_any_classes, can_retransform_any_classes and IsModifiableClass API to
|
||||||
|
disallow some implementation defined classes.
|
||||||
|
</change>
|
||||||
</changehistory>
|
</changehistory>
|
||||||
|
|
||||||
</specification>
|
</specification>
|
||||||
|
@ -283,7 +283,7 @@ JvmtiEnv::RetransformClasses(jint class_count, const jclass* classes) {
|
|||||||
return JVMTI_ERROR_INVALID_CLASS;
|
return JVMTI_ERROR_INVALID_CLASS;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (java_lang_Class::is_primitive(k_mirror)) {
|
if (!VM_RedefineClasses::is_modifiable_class(k_mirror)) {
|
||||||
return JVMTI_ERROR_UNMODIFIABLE_CLASS;
|
return JVMTI_ERROR_UNMODIFIABLE_CLASS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -294,9 +294,6 @@ JvmtiEnv::RetransformClasses(jint class_count, const jclass* classes) {
|
|||||||
if (status & (JVMTI_CLASS_STATUS_ERROR)) {
|
if (status & (JVMTI_CLASS_STATUS_ERROR)) {
|
||||||
return JVMTI_ERROR_INVALID_CLASS;
|
return JVMTI_ERROR_INVALID_CLASS;
|
||||||
}
|
}
|
||||||
if (status & (JVMTI_CLASS_STATUS_ARRAY)) {
|
|
||||||
return JVMTI_ERROR_UNMODIFIABLE_CLASS;
|
|
||||||
}
|
|
||||||
|
|
||||||
instanceKlassHandle ikh(current_thread, k_oop);
|
instanceKlassHandle ikh(current_thread, k_oop);
|
||||||
if (ikh->get_cached_class_file_bytes() == NULL) {
|
if (ikh->get_cached_class_file_bytes() == NULL) {
|
||||||
|
@ -130,7 +130,7 @@ bool VM_RedefineClasses::doit_prologue() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
oop mirror = JNIHandles::resolve_non_null(_class_defs[i].klass);
|
oop mirror = JNIHandles::resolve_non_null(_class_defs[i].klass);
|
||||||
// classes for primitives and arrays cannot be redefined
|
// classes for primitives and arrays and vm anonymous classes cannot be redefined
|
||||||
// check here so following code can assume these classes are InstanceKlass
|
// check here so following code can assume these classes are InstanceKlass
|
||||||
if (!is_modifiable_class(mirror)) {
|
if (!is_modifiable_class(mirror)) {
|
||||||
_res = JVMTI_ERROR_UNMODIFIABLE_CLASS;
|
_res = JVMTI_ERROR_UNMODIFIABLE_CLASS;
|
||||||
@ -250,9 +250,14 @@ bool VM_RedefineClasses::is_modifiable_class(oop klass_mirror) {
|
|||||||
if (java_lang_Class::is_primitive(klass_mirror)) {
|
if (java_lang_Class::is_primitive(klass_mirror)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
Klass* the_class_oop = java_lang_Class::as_Klass(klass_mirror);
|
Klass* k = java_lang_Class::as_Klass(klass_mirror);
|
||||||
// classes for arrays cannot be redefined
|
// classes for arrays cannot be redefined
|
||||||
if (the_class_oop == NULL || !the_class_oop->is_instance_klass()) {
|
if (k == NULL || !k->is_instance_klass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cannot redefine or retransform an anonymous class.
|
||||||
|
if (InstanceKlass::cast(k)->is_anonymous()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
171
hotspot/test/runtime/RedefineTests/ModifyAnonymous.java
Normal file
171
hotspot/test/runtime/RedefineTests/ModifyAnonymous.java
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
* @library /test/lib
|
||||||
|
* @summary Test that retransforming and redefining anonymous classes gets UnmodifiableClassException
|
||||||
|
* @modules java.base/jdk.internal.misc
|
||||||
|
* @modules java.instrument
|
||||||
|
* jdk.jartool/sun.tools.jar
|
||||||
|
* @run main ModifyAnonymous buildagent
|
||||||
|
* @run main/othervm -javaagent:redefineagent.jar ModifyAnonymous
|
||||||
|
*/
|
||||||
|
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.PrintWriter;
|
||||||
|
import java.lang.NoSuchFieldException;
|
||||||
|
import java.lang.NoSuchMethodException;
|
||||||
|
import java.lang.RuntimeException;
|
||||||
|
import java.lang.instrument.ClassDefinition;
|
||||||
|
import java.lang.instrument.ClassFileTransformer;
|
||||||
|
import java.lang.instrument.IllegalClassFormatException;
|
||||||
|
import java.lang.instrument.Instrumentation;
|
||||||
|
import java.security.ProtectionDomain;
|
||||||
|
import jdk.test.lib.*;
|
||||||
|
|
||||||
|
public class ModifyAnonymous {
|
||||||
|
|
||||||
|
public static class LambdaTransformer implements ClassFileTransformer {
|
||||||
|
@Override
|
||||||
|
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined,
|
||||||
|
ProtectionDomain protectionDomain, byte[] classfileBuffer)
|
||||||
|
throws IllegalClassFormatException {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static Instrumentation inst = null;
|
||||||
|
static volatile boolean done = false;
|
||||||
|
|
||||||
|
public static void premain(String args, Instrumentation instrumentation) {
|
||||||
|
|
||||||
|
inst = instrumentation;
|
||||||
|
System.out.println("javaagent in da house!");
|
||||||
|
instrumentation.addTransformer(new LambdaTransformer());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void buildAgent() {
|
||||||
|
try {
|
||||||
|
ClassFileInstaller.main("ModifyAnonymous");
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("Could not write agent classfile", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
PrintWriter pw = new PrintWriter("MANIFEST.MF");
|
||||||
|
pw.println("Premain-Class: ModifyAnonymous");
|
||||||
|
pw.println("Agent-Class: ModifyAnonymous");
|
||||||
|
pw.println("Can-Retransform-Classes: true");
|
||||||
|
pw.println("Can-Redefine-Classes: true");
|
||||||
|
pw.close();
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
throw new RuntimeException("Could not write manifest file for the agent", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
sun.tools.jar.Main jarTool = new sun.tools.jar.Main(System.out, System.err, "jar");
|
||||||
|
if (!jarTool.run(new String[] { "-cmf", "MANIFEST.MF", "redefineagent.jar", "ModifyAnonymous.class" })) {
|
||||||
|
throw new RuntimeException("Could not write the agent jar file");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class InstanceMethodCallSiteApp {
|
||||||
|
|
||||||
|
public static void test() throws InterruptedException {
|
||||||
|
for (int i = 0; i < 2; i++) {
|
||||||
|
InstanceMethodCallSiteApp app = new InstanceMethodCallSiteApp();
|
||||||
|
Runnable r = app::doWork; // this creates an anonymous class
|
||||||
|
while (!done) {
|
||||||
|
r.run();
|
||||||
|
Thread.sleep(10);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void doWork() {
|
||||||
|
System.out.print(".");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void runTest() {
|
||||||
|
while (!done) {
|
||||||
|
Class[] allLoadedClasses = inst.getAllLoadedClasses();
|
||||||
|
for (Class clazz : allLoadedClasses) {
|
||||||
|
final String name = clazz.getName();
|
||||||
|
if (name.contains("$$Lambda$") && name.contains("App")) {
|
||||||
|
if (inst.isModifiableClass(clazz)) {
|
||||||
|
throw new RuntimeException ("Class should not be modifiable");
|
||||||
|
}
|
||||||
|
// Try to modify them anyway.
|
||||||
|
try {
|
||||||
|
System.out.println("retransform called for " + name);
|
||||||
|
inst.retransformClasses(clazz);
|
||||||
|
} catch(java.lang.instrument.UnmodifiableClassException t) {
|
||||||
|
System.out.println("PASSED: expecting UnmodifiableClassException");
|
||||||
|
t.printStackTrace();
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
System.out.println("redefine called for " + name);
|
||||||
|
String newclass = "class Dummy {}";
|
||||||
|
byte[] bytecode = InMemoryJavaCompiler.compile("Dummy", newclass);
|
||||||
|
ClassDefinition cld = new ClassDefinition(clazz, bytecode);
|
||||||
|
inst.redefineClasses(new ClassDefinition[] { cld });
|
||||||
|
} catch(java.lang.instrument.UnmodifiableClassException t) {
|
||||||
|
System.out.println("PASSED: expecting UnmodifiableClassException");
|
||||||
|
t.printStackTrace();
|
||||||
|
} catch(java.lang.ClassNotFoundException e) {
|
||||||
|
throw new RuntimeException ("ClassNotFoundException thrown");
|
||||||
|
}
|
||||||
|
done = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String argv[]) throws InterruptedException, RuntimeException {
|
||||||
|
if (argv.length == 1 && argv[0].equals("buildagent")) {
|
||||||
|
buildAgent();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inst == null) {
|
||||||
|
throw new RuntimeException("Instrumentation object was null");
|
||||||
|
}
|
||||||
|
|
||||||
|
new Thread() {
|
||||||
|
public void run() {
|
||||||
|
runTest();
|
||||||
|
}
|
||||||
|
}.start();
|
||||||
|
|
||||||
|
// Test that NCDFE is not thrown for anonymous class:
|
||||||
|
// ModifyAnonymous$InstanceMethodCallSiteApp$$Lambda$18
|
||||||
|
try {
|
||||||
|
ModifyAnonymous test = new ModifyAnonymous();
|
||||||
|
InstanceMethodCallSiteApp.test();
|
||||||
|
} catch (NoClassDefFoundError e) {
|
||||||
|
throw new RuntimeException("FAILED: NoClassDefFoundError thrown for " + e.getMessage());
|
||||||
|
}
|
||||||
|
System.out.println("PASSED: NoClassDefFound error not thrown");
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user