Skip to content

Commit 1d2c7ac

Browse files
committed
8267555: Fix class file version during redefinition after 8238048
Reviewed-by: coleenp, sspitsyn
1 parent 97ec5ad commit 1d2c7ac

File tree

5 files changed

+207
-4
lines changed

5 files changed

+207
-4
lines changed

src/hotspot/share/oops/constantPool.cpp

-1
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,6 @@ void ConstantPool::copy_fields(const ConstantPool* orig) {
7373
set_has_dynamic_constant();
7474
}
7575

76-
// Copy class version
7776
set_major_version(orig->major_version());
7877
set_minor_version(orig->minor_version());
7978

src/hotspot/share/prims/jvmtiRedefineClasses.cpp

+16-3
Original file line numberDiff line numberDiff line change
@@ -1852,9 +1852,12 @@ jvmtiError VM_RedefineClasses::merge_cp_and_rewrite(
18521852
return JVMTI_ERROR_INTERNAL;
18531853
}
18541854

1855-
// Save fields from the old_cp.
1856-
merge_cp->copy_fields(old_cp());
1857-
scratch_cp->copy_fields(old_cp());
1855+
// Set dynamic constants attribute from the original CP.
1856+
if (old_cp->has_dynamic_constant()) {
1857+
scratch_cp->set_has_dynamic_constant();
1858+
}
1859+
// Copy attributes from scratch_cp to merge_cp
1860+
merge_cp->copy_fields(scratch_cp());
18581861

18591862
log_info(redefine, class, constantpool)("merge_cp_len=%d, index_map_len=%d", merge_cp_length, _index_map_count);
18601863

@@ -4396,6 +4399,16 @@ void VM_RedefineClasses::redefine_single_class(Thread* current, jclass the_jclas
43964399

43974400
swap_annotations(the_class, scratch_class);
43984401

4402+
// Replace minor version number of class file
4403+
u2 old_minor_version = the_class->constants()->minor_version();
4404+
the_class->constants()->set_minor_version(scratch_class->constants()->minor_version());
4405+
scratch_class->constants()->set_minor_version(old_minor_version);
4406+
4407+
// Replace major version number of class file
4408+
u2 old_major_version = the_class->constants()->major_version();
4409+
the_class->constants()->set_major_version(scratch_class->constants()->major_version());
4410+
scratch_class->constants()->set_major_version(old_major_version);
4411+
43994412
// Replace CP indexes for class and name+type of enclosing method
44004413
u2 old_class_idx = the_class->enclosing_method_class_index();
44014414
u2 old_method_idx = the_class->enclosing_method_method_index();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
/*
2+
* Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
24+
/*
25+
* @test
26+
* @bug 8267555
27+
* @requires vm.jvmti
28+
* @summary Class redefinition with a different class file version
29+
* @library /test/lib
30+
* @compile TestClassOld.jasm TestClassNew.jasm
31+
* @run main RedefineClassHelper
32+
* @run main/othervm -javaagent:redefineagent.jar ClassVersionAfterRedefine
33+
*/
34+
35+
import java.io.InputStream;
36+
import java.lang.reflect.Method;
37+
38+
import static jdk.test.lib.Asserts.assertTrue;
39+
40+
public class ClassVersionAfterRedefine extends ClassLoader {
41+
42+
private static String myName = ClassVersionAfterRedefine.class.getName();
43+
44+
private static byte[] getBytecodes(String name) throws Exception {
45+
InputStream is = ClassVersionAfterRedefine.class.getResourceAsStream(name + ".class");
46+
byte[] buf = is.readAllBytes();
47+
System.out.println("sizeof(" + name + ".class) == " + buf.length);
48+
return buf;
49+
}
50+
51+
private static int getStringIndex(String needle, byte[] buf) {
52+
return getStringIndex(needle, buf, 0);
53+
}
54+
55+
private static int getStringIndex(String needle, byte[] buf, int offset) {
56+
outer:
57+
for (int i = offset; i < buf.length - offset - needle.length(); i++) {
58+
for (int j = 0; j < needle.length(); j++) {
59+
if (buf[i + j] != (byte)needle.charAt(j)) continue outer;
60+
}
61+
return i;
62+
}
63+
return 0;
64+
}
65+
66+
private static void replaceString(byte[] buf, String name, int index) {
67+
for (int i = index; i < index + name.length(); i++) {
68+
buf[i] = (byte)name.charAt(i - index);
69+
}
70+
}
71+
72+
private static void replaceAllStrings(byte[] buf, String oldString, String newString) throws Exception {
73+
assertTrue(oldString.length() == newString.length(), "must have same length");
74+
int index = -1;
75+
while ((index = getStringIndex(oldString, buf, index + 1)) != 0) {
76+
replaceString(buf, newString, index);
77+
}
78+
}
79+
80+
public static void main(String[] s) throws Exception {
81+
82+
byte[] buf = getBytecodes("TestClassOld");
83+
// Poor man's renaming of class "TestClassOld" to "TestClassXXX"
84+
replaceAllStrings(buf, "TestClassOld", "TestClassXXX");
85+
ClassVersionAfterRedefine cvar = new ClassVersionAfterRedefine();
86+
Class<?> old = cvar.defineClass(null, buf, 0, buf.length);
87+
Method foo = old.getMethod("foo");
88+
Object result = foo.invoke(null);
89+
assertTrue("java-lang-String".equals(result));
90+
System.out.println(old.getSimpleName() + ".foo() = " + result);
91+
92+
buf = getBytecodes("TestClassNew");
93+
// Rename class "TestClassNew" to "TestClassXXX" so we can use it for
94+
// redefining the original version of "TestClassXXX" (i.e. "TestClassOld").
95+
replaceAllStrings(buf, "TestClassNew", "TestClassXXX");
96+
// Now redine the original version of "TestClassXXX" (i.e. "TestClassOld").
97+
RedefineClassHelper.redefineClass(old, buf);
98+
result = foo.invoke(null);
99+
assertTrue("java.lang.String".equals(result));
100+
System.out.println(old.getSimpleName() + ".foo() = " + result);
101+
}
102+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/*
2+
* Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
24+
super public final class TestClassNew version 49:0 {
25+
26+
public Method "<init>":"()V" stack 1 locals 1 {
27+
aload_0;
28+
invokespecial Method java/lang/Object."<init>":"()V";
29+
return;
30+
}
31+
32+
public static Method foo:"()Ljava/lang/String;" stack 1 locals 1 {
33+
ldc class java/lang/String;
34+
invokevirtual Method java/lang/Class.getName:"()Ljava/lang/String;";
35+
areturn;
36+
}
37+
38+
public static Method main:"([Ljava/lang/String;)V" stack 2 locals 2 {
39+
getstatic Field java/lang/System.out:"Ljava/io/PrintStream;";
40+
invokestatic Method TestClassNew.foo:"()Ljava/lang/String;";
41+
invokevirtual Method java/io/PrintStream.println:"(Ljava/lang/String;)V";
42+
return;
43+
}
44+
45+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
* Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
24+
super public final class TestClassOld version 48:0 {
25+
26+
public Method "<init>":"()V" stack 1 locals 1 {
27+
aload_0;
28+
invokespecial Method java/lang/Object."<init>":"()V";
29+
return;
30+
}
31+
32+
public static Method foo:"()Ljava/lang/String;" stack 1 locals 1 {
33+
ldc String "java-lang-String";
34+
areturn;
35+
}
36+
37+
public static Method main:"([Ljava/lang/String;)V" stack 2 locals 2 {
38+
getstatic Field java/lang/System.out:"Ljava/io/PrintStream;";
39+
invokestatic Method TestClassOld.foo:"()Ljava/lang/String;";
40+
invokevirtual Method java/io/PrintStream.println:"(Ljava/lang/String;)V";
41+
return;
42+
}
43+
44+
}

0 commit comments

Comments
 (0)