mirror of
https://github.com/openjdk/jdk.git
synced 2026-01-28 03:58:21 +00:00
8376185: NoSuchFieldError thrown after a record with type annotation retransformed
Fix a retransform error when retransforming a record with type annotation. processing the record type annotation was done by calling the wrong method and using the one to process regular annotation. Regular annotations have not the same structure and decoding was therefore incorrect. The decoding methods detect a problem but this error was not propagated correctly outside of VM_RedfineClass::load_new_class_versions method, swallowing the error and leaving the retransformed class in bad state. Here we have fixed the call to the right method for decoding the type annotations but also propagated the error when rewriting the constant pool as an JVMTI_ERROR_INTERNAL
This commit is contained in:
parent
a40dbce495
commit
44981e6b69
@ -0,0 +1,24 @@
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@MyTypeAnnotation
|
||||
public record MyRecord(@MyTypeUseAnnotation String filter) {
|
||||
public static MyRecord parse(String param) {
|
||||
if (param == null) {
|
||||
throw new IllegalArgumentException("Filter cannot be null");
|
||||
}
|
||||
return new MyRecord(param);
|
||||
}
|
||||
}
|
||||
|
||||
@Target({ElementType.TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@interface MyTypeAnnotation {
|
||||
}
|
||||
|
||||
@Target({ ElementType.TYPE_USE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@interface MyTypeUseAnnotation {
|
||||
}
|
||||
@ -0,0 +1,64 @@
|
||||
/*
|
||||
* @test
|
||||
* @bug 8376185
|
||||
* @summary Class retransformation on a record type annotation
|
||||
* @comment This is will rewrite the constant pool and process
|
||||
* @comment the type annotation
|
||||
* @library /test/lib
|
||||
* @modules java.base/jdk.internal.misc
|
||||
* @modules java.compiler
|
||||
* java.instrument
|
||||
* @compile ../NamedBuffer.java
|
||||
* @compile altered/MyRecord.jcod
|
||||
* @run shell rename.sh
|
||||
* @compile MyRecord.java
|
||||
* @run main RedefineClassHelper
|
||||
* @run main/othervm -javaagent:redefineagent.jar -Xlog:redefine*=debug TestRetransformRecord
|
||||
*/
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.lang.instrument.ClassFileTransformer;
|
||||
import java.lang.instrument.Instrumentation;
|
||||
import java.security.ProtectionDomain;
|
||||
|
||||
public class TestRetransformRecord {
|
||||
static final String SRC = System.getProperty("test.src");
|
||||
static final String DEST = System.getProperty("test.classes");
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
MyRecord.parse("foo");
|
||||
File clsfile = new File(DEST + "/altered/MyRecord.class");
|
||||
byte[] buf = null;
|
||||
try (FileInputStream str = new FileInputStream(clsfile)) {
|
||||
buf = NamedBuffer.loadBufferFromStream(str);
|
||||
}
|
||||
Instrumentation inst = RedefineClassHelper.instrumentation;
|
||||
inst.addTransformer(new IdentityTransformer("MyRecord", buf), true);
|
||||
inst.retransformClasses(MyRecord.class);
|
||||
System.out.println(MyRecord.parse("foo"));
|
||||
}
|
||||
}
|
||||
|
||||
class IdentityTransformer implements ClassFileTransformer {
|
||||
private final String className;
|
||||
private final byte[] buffer;
|
||||
|
||||
public IdentityTransformer(String className, byte[] buffer) {
|
||||
this.className = className;
|
||||
this.buffer = buffer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] transform(ClassLoader loader,
|
||||
String classPath,
|
||||
Class<?> classBeingRedefined,
|
||||
ProtectionDomain protectionDomain,
|
||||
byte[] classfileBuffer) {
|
||||
if (classPath != null && classPath.equals(className.replace('.', '/'))) {
|
||||
System.out.println("Transforming " + className);
|
||||
return buffer;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,390 @@
|
||||
class MyRecord {
|
||||
0xCAFEBABE;
|
||||
0; // minor version
|
||||
69; // version
|
||||
[] { // Constant Pool
|
||||
; // first element is empty
|
||||
Method #2 #3; // #1
|
||||
Class #4; // #2
|
||||
NameAndType #5 #6; // #3
|
||||
Utf8 "java/lang/Record"; // #4
|
||||
Utf8 "<init>"; // #5
|
||||
Utf8 "()V"; // #6
|
||||
Field #8 #9; // #7
|
||||
Class #11; // #8
|
||||
NameAndType #10 #12; // #9
|
||||
Utf8 "filter"; // #10
|
||||
Utf8 "MyRecord"; // #11
|
||||
Utf8 "Ljava/lang/String;"; // #12
|
||||
Class #34; // #13
|
||||
Utf8 "LMyTypeUseAnnotation;"; // #14
|
||||
String #16; // #15
|
||||
Utf8 "Filter cannot be null"; // #16
|
||||
Method #13 #18; // #17
|
||||
NameAndType #5 #19; // #18
|
||||
Utf8 "(Ljava/lang/String;)V"; // #19
|
||||
Method #8 #18; // #20
|
||||
InvokeDynamic 0s #22; // #21
|
||||
NameAndType #23 #24; // #22
|
||||
Utf8 "toString"; // #23
|
||||
Utf8 "(LMyRecord;)Ljava/lang/String;"; // #24
|
||||
InvokeDynamic 0s #26; // #25
|
||||
NameAndType #27 #28; // #26
|
||||
Utf8 "hashCode"; // #27
|
||||
Utf8 "(LMyRecord;)I"; // #28
|
||||
InvokeDynamic 0s #30; // #29
|
||||
NameAndType #31 #32; // #30
|
||||
Utf8 "equals"; // #31
|
||||
Utf8 "(LMyRecord;Ljava/lang/Object;)Z"; // #32
|
||||
Utf8 "RuntimeVisibleTypeAnnotations"; // #33
|
||||
Utf8 "java/lang/IllegalArgumentException"; // #34
|
||||
Utf8 "Code"; // #35
|
||||
Utf8 "LineNumberTable"; // #36
|
||||
Utf8 "LocalVariableTable"; // #37
|
||||
Utf8 "this"; // #38
|
||||
Utf8 "LMyRecord;"; // #39
|
||||
Utf8 "MethodParameters"; // #40
|
||||
Utf8 "parse"; // #41
|
||||
Utf8 "(Ljava/lang/String;)LMyRecord;"; // #42
|
||||
Utf8 "param"; // #43
|
||||
Utf8 "StackMapTable"; // #44
|
||||
Utf8 "()Ljava/lang/String;"; // #45
|
||||
Utf8 "()I"; // #46
|
||||
Utf8 "(Ljava/lang/Object;)Z"; // #47
|
||||
Utf8 "o"; // #48
|
||||
Utf8 "Ljava/lang/Object;"; // #49
|
||||
Utf8 "SourceFile"; // #50
|
||||
Utf8 "MyRecord.java"; // #51
|
||||
Utf8 "RuntimeVisibleAnnotations"; // #52
|
||||
Utf8 "LMyTypeAnnotation;"; // #53
|
||||
Utf8 "Record"; // #54
|
||||
Utf8 "BootstrapMethods"; // #55
|
||||
String #10; // #56
|
||||
MethodHandle 1b #7; // #57
|
||||
MethodHandle 6b #59; // #58
|
||||
Method #60 #61; // #59
|
||||
Class #62; // #60
|
||||
NameAndType #63 #64; // #61
|
||||
Utf8 "java/lang/runtime/ObjectMethods"; // #62
|
||||
Utf8 "bootstrap"; // #63
|
||||
Utf8 "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/TypeDescriptor;Ljava/lang/Class;Ljava/lang/String;[Ljava/lang/invoke/MethodHandle;)Ljava/lang/Object;"; // #64
|
||||
Utf8 "InnerClasses"; // #65
|
||||
Class #67; // #66
|
||||
Utf8 "java/lang/invoke/MethodHandles$Lookup"; // #67
|
||||
Class #69; // #68
|
||||
Utf8 "java/lang/invoke/MethodHandles"; // #69
|
||||
Utf8 "Lookup"; // #70
|
||||
}
|
||||
|
||||
0x0031; // access
|
||||
#8; // this_cpx
|
||||
#2; // super_cpx
|
||||
|
||||
[] { // Interfaces
|
||||
} // end of Interfaces
|
||||
|
||||
[] { // Fields
|
||||
{ // field
|
||||
0x0012; // access
|
||||
#10; // name_index
|
||||
#12; // descriptor_index
|
||||
[] { // Attributes
|
||||
Attr(#33) { // RuntimeVisibleTypeAnnotations
|
||||
[] { // annotations
|
||||
{ // type_annotation
|
||||
0x13; // target_type: FIELD
|
||||
[]b { // type_paths
|
||||
}
|
||||
#14;
|
||||
[] { // element_value_pairs
|
||||
} // element_value_pairs
|
||||
} // type_annotation
|
||||
}
|
||||
} // end of RuntimeVisibleTypeAnnotations
|
||||
} // end of Attributes
|
||||
}
|
||||
} // end of Fields
|
||||
|
||||
[] { // Methods
|
||||
{ // method
|
||||
0x0001; // access
|
||||
#5; // name_index
|
||||
#19; // descriptor_index
|
||||
[] { // Attributes
|
||||
Attr(#35) { // Code
|
||||
2; // max_stack
|
||||
2; // max_locals
|
||||
Bytes[]{
|
||||
0x2A 0xB7 0x00 0x01 0x2A 0x2B 0xB5 0x00 0x07 0xB1;
|
||||
}
|
||||
[] { // Traps
|
||||
} // end of Traps
|
||||
[] { // Attributes
|
||||
Attr(#36) { // LineNumberTable
|
||||
[] { // line_number_table
|
||||
0 7;
|
||||
}
|
||||
} // end of LineNumberTable
|
||||
;
|
||||
Attr(#37) { // LocalVariableTable
|
||||
[] { // LocalVariableTable
|
||||
0 10 38 39 0;
|
||||
0 10 11 12 1;
|
||||
}
|
||||
} // end of LocalVariableTable
|
||||
} // end of Attributes
|
||||
} // end of Code
|
||||
;
|
||||
Attr(#40) { // MethodParameters
|
||||
[]b { // MethodParameters
|
||||
#10 0x0000;
|
||||
}
|
||||
} // end of MethodParameters
|
||||
;
|
||||
Attr(#33) { // RuntimeVisibleTypeAnnotations
|
||||
[] { // annotations
|
||||
{ // type_annotation
|
||||
0x16; // target_type: METHOD_FORMAL_PARAMETER
|
||||
0x00; // parameter_index
|
||||
[]b { // type_paths
|
||||
}
|
||||
#14;
|
||||
[] { // element_value_pairs
|
||||
} // element_value_pairs
|
||||
} // type_annotation
|
||||
}
|
||||
} // end of RuntimeVisibleTypeAnnotations
|
||||
} // end of Attributes
|
||||
}
|
||||
;
|
||||
{ // method
|
||||
0x0009; // access
|
||||
#41; // name_index
|
||||
#42; // descriptor_index
|
||||
[] { // Attributes
|
||||
Attr(#35) { // Code
|
||||
3; // max_stack
|
||||
1; // max_locals
|
||||
Bytes[]{
|
||||
0x2A 0xC7 0x00 0x0D 0xBB 0x00 0x0D 0x59 0x12 0x0F 0xB7 0x00;
|
||||
0x11 0xBF 0xBB 0x00 0x08 0x59 0x2A 0xB7 0x00 0x14 0xB0;
|
||||
}
|
||||
[] { // Traps
|
||||
} // end of Traps
|
||||
[] { // Attributes
|
||||
Attr(#36) { // LineNumberTable
|
||||
[] { // line_number_table
|
||||
0 9;
|
||||
4 10;
|
||||
14 12;
|
||||
}
|
||||
} // end of LineNumberTable
|
||||
;
|
||||
Attr(#37) { // LocalVariableTable
|
||||
[] { // LocalVariableTable
|
||||
0 23 43 12 0;
|
||||
}
|
||||
} // end of LocalVariableTable
|
||||
;
|
||||
Attr(#44) { // StackMapTable
|
||||
[] { //
|
||||
14b; // same_frame
|
||||
}
|
||||
} // end of StackMapTable
|
||||
} // end of Attributes
|
||||
} // end of Code
|
||||
} // end of Attributes
|
||||
}
|
||||
;
|
||||
{ // method
|
||||
0x0011; // access
|
||||
#23; // name_index
|
||||
#45; // descriptor_index
|
||||
[] { // Attributes
|
||||
Attr(#35) { // Code
|
||||
1; // max_stack
|
||||
1; // max_locals
|
||||
Bytes[]{
|
||||
0x2A 0xBA 0x00 0x15 0x00 0x00 0xB0;
|
||||
}
|
||||
[] { // Traps
|
||||
} // end of Traps
|
||||
[] { // Attributes
|
||||
Attr(#36) { // LineNumberTable
|
||||
[] { // line_number_table
|
||||
0 6;
|
||||
}
|
||||
} // end of LineNumberTable
|
||||
;
|
||||
Attr(#37) { // LocalVariableTable
|
||||
[] { // LocalVariableTable
|
||||
0 7 38 39 0;
|
||||
}
|
||||
} // end of LocalVariableTable
|
||||
} // end of Attributes
|
||||
} // end of Code
|
||||
} // end of Attributes
|
||||
}
|
||||
;
|
||||
{ // method
|
||||
0x0011; // access
|
||||
#27; // name_index
|
||||
#46; // descriptor_index
|
||||
[] { // Attributes
|
||||
Attr(#35) { // Code
|
||||
1; // max_stack
|
||||
1; // max_locals
|
||||
Bytes[]{
|
||||
0x2A 0xBA 0x00 0x19 0x00 0x00 0xAC;
|
||||
}
|
||||
[] { // Traps
|
||||
} // end of Traps
|
||||
[] { // Attributes
|
||||
Attr(#36) { // LineNumberTable
|
||||
[] { // line_number_table
|
||||
0 6;
|
||||
}
|
||||
} // end of LineNumberTable
|
||||
;
|
||||
Attr(#37) { // LocalVariableTable
|
||||
[] { // LocalVariableTable
|
||||
0 7 38 39 0;
|
||||
}
|
||||
} // end of LocalVariableTable
|
||||
} // end of Attributes
|
||||
} // end of Code
|
||||
} // end of Attributes
|
||||
}
|
||||
;
|
||||
{ // method
|
||||
0x0011; // access
|
||||
#31; // name_index
|
||||
#47; // descriptor_index
|
||||
[] { // Attributes
|
||||
Attr(#35) { // Code
|
||||
2; // max_stack
|
||||
2; // max_locals
|
||||
Bytes[]{
|
||||
0x2A 0x2B 0xBA 0x00 0x1D 0x00 0x00 0xAC }
|
||||
[] { // Traps
|
||||
} // end of Traps
|
||||
[] { // Attributes
|
||||
Attr(#36) { // LineNumberTable
|
||||
[] { // line_number_table
|
||||
0 6;
|
||||
}
|
||||
} // end of LineNumberTable
|
||||
;
|
||||
Attr(#37) { // LocalVariableTable
|
||||
[] { // LocalVariableTable
|
||||
0 8 38 39 0;
|
||||
0 8 48 49 1;
|
||||
}
|
||||
} // end of LocalVariableTable
|
||||
} // end of Attributes
|
||||
} // end of Code
|
||||
} // end of Attributes
|
||||
}
|
||||
;
|
||||
{ // method
|
||||
0x0001; // access
|
||||
#10; // name_index
|
||||
#45; // descriptor_index
|
||||
[] { // Attributes
|
||||
Attr(#35) { // Code
|
||||
1; // max_stack
|
||||
1; // max_locals
|
||||
Bytes[]{
|
||||
0x2A 0xB4 0x00 0x07 0xB0;
|
||||
}
|
||||
[] { // Traps
|
||||
} // end of Traps
|
||||
[] { // Attributes
|
||||
Attr(#36) { // LineNumberTable
|
||||
[] { // line_number_table
|
||||
0 6;
|
||||
}
|
||||
} // end of LineNumberTable
|
||||
;
|
||||
Attr(#37) { // LocalVariableTable
|
||||
[] { // LocalVariableTable
|
||||
0 5 38 39 0;
|
||||
}
|
||||
} // end of LocalVariableTable
|
||||
} // end of Attributes
|
||||
} // end of Code
|
||||
;
|
||||
Attr(#33) { // RuntimeVisibleTypeAnnotations
|
||||
[] { // annotations
|
||||
{ // type_annotation
|
||||
0x14; // target_type: METHOD_RETURN
|
||||
[]b { // type_paths
|
||||
}
|
||||
#14;
|
||||
[] { // element_value_pairs
|
||||
} // element_value_pairs
|
||||
} // type_annotation
|
||||
}
|
||||
} // end of RuntimeVisibleTypeAnnotations
|
||||
} // end of Attributes
|
||||
}
|
||||
} // end of Methods
|
||||
|
||||
[] { // Attributes
|
||||
Attr(#50) { // SourceFile
|
||||
#51;
|
||||
} // end of SourceFile
|
||||
;
|
||||
Attr(#52) { // RuntimeVisibleAnnotations
|
||||
[] { // annotations
|
||||
{ // annotation
|
||||
#53;
|
||||
[] { // element_value_pairs
|
||||
} // element_value_pairs
|
||||
} // annotation
|
||||
}
|
||||
} // end of RuntimeVisibleAnnotations
|
||||
;
|
||||
Attr(#54) { // Record
|
||||
[] { // components
|
||||
{ // component
|
||||
#10; // name_index
|
||||
#12; // descriptor_index
|
||||
[] { // Attributes
|
||||
Attr(#33) { // RuntimeVisibleTypeAnnotations
|
||||
[] { // annotations
|
||||
{ // type_annotation
|
||||
0x13; // target_type: FIELD
|
||||
[]b { // type_paths
|
||||
}
|
||||
#14;
|
||||
[] { // element_value_pairs
|
||||
} // element_value_pairs
|
||||
} // type_annotation
|
||||
}
|
||||
} // end of RuntimeVisibleTypeAnnotations
|
||||
} // end of Attributes
|
||||
}
|
||||
}
|
||||
} // end of Record
|
||||
;
|
||||
Attr(#55) { // BootstrapMethods
|
||||
[] { // bootstrap_methods
|
||||
{ // bootstrap_method
|
||||
#58; // bootstrap_method_ref
|
||||
[] { // bootstrap_arguments
|
||||
#8;
|
||||
#56;
|
||||
#57;
|
||||
} // bootstrap_arguments
|
||||
} // bootstrap_method
|
||||
}
|
||||
} // end of BootstrapMethods
|
||||
;
|
||||
Attr(#65) { // InnerClasses
|
||||
[] { // classes
|
||||
#66 #68 #70 25;
|
||||
}
|
||||
} // end of InnerClasses
|
||||
} // end of Attributes
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
#!/bin/sh
|
||||
mkdir $TESTCLASSES/altered
|
||||
mv $TESTCLASSES/MyRecord.class $TESTCLASSES/altered/MyRecord.class
|
||||
Loading…
x
Reference in New Issue
Block a user