Skip to content

Instantly share code, notes, and snippets.

@marchof
Last active August 29, 2015 14:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save marchof/070ee2c2077bd095ba96 to your computer and use it in GitHub Desktop.
Save marchof/070ee2c2077bd095ba96 to your computer and use it in GitHub Desktop.
Reproducer for invalid annotation ranges on bridge methods (javac 1.8.0_31)
PROBLEM
Annotation with target TYPE_USE seems to be copied to bridge methods. As bridge methods
only delegate back to the overloaded method, these annotations are typically invalid.
The reproducer shows that the type annotations specifies a PC range which is longer
than the byte code of the method.
Probably type annotations shouldn't be copied to bridge methods.
REPRODUCER
The annotation with target TYPE_USE in the method doit(java.lang.Runnable) is copied
to the bridge method doit(java.lang.Object). While the bridge method only has 8
instructions, the range of the type annotation has a length of 15.
Classfile ClassWithBridgeMethod.class
Last modified 19.02.2015; size 654 bytes
MD5 checksum b81ccd384e2806ff7c6c08741412ddbb
public class ClassWithBridgeMethod<T extends java.lang.Runnable> extends java.lang.Object implements ParameterizedInterface<T>
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref #7.#20 // java/lang/Object."<init>":()V
#2 = Fieldref #21.#22 // java/lang/System.out:Ljava/io/PrintStream;
#3 = Methodref #23.#24 // java/io/PrintStream.println:(Ljava/lang/Object;)V
#4 = Class #25 // java/lang/Runnable
#5 = Methodref #6.#26 // ClassWithBridgeMethod.doit:(Ljava/lang/Runnable;)V
#6 = Class #27 // ClassWithBridgeMethod
#7 = Class #28 // java/lang/Object
#8 = Class #29 // ParameterizedInterface
#9 = Utf8 <init>
#10 = Utf8 ()V
#11 = Utf8 Code
#12 = Utf8 doit
#13 = Utf8 (Ljava/lang/Runnable;)V
#14 = Utf8 RuntimeInvisibleTypeAnnotations
#15 = Utf8 LTypeUseAnnotation;
#16 = Utf8 Signature
#17 = Utf8 (TT;)V
#18 = Utf8 (Ljava/lang/Object;)V
#19 = Utf8 <T::Ljava/lang/Runnable;>Ljava/lang/Object;LParameterizedInterface<TT;>;
#20 = NameAndType #9:#10 // "<init>":()V
#21 = Class #30 // java/lang/System
#22 = NameAndType #31:#32 // out:Ljava/io/PrintStream;
#23 = Class #33 // java/io/PrintStream
#24 = NameAndType #34:#18 // println:(Ljava/lang/Object;)V
#25 = Utf8 java/lang/Runnable
#26 = NameAndType #12:#13 // doit:(Ljava/lang/Runnable;)V
#27 = Utf8 ClassWithBridgeMethod
#28 = Utf8 java/lang/Object
#29 = Utf8 ParameterizedInterface
#30 = Utf8 java/lang/System
#31 = Utf8 out
#32 = Utf8 Ljava/io/PrintStream;
#33 = Utf8 java/io/PrintStream
#34 = Utf8 println
{
public ClassWithBridgeMethod();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public void doit(T);
descriptor: (Ljava/lang/Runnable;)V
flags: ACC_PUBLIC
Code:
stack=2, locals=3, args_size=2
0: aconst_null
1: astore_2
2: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
5: aload_2
6: invokevirtual #3 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
9: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
12: aload_2
13: invokevirtual #3 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
16: return
RuntimeInvisibleTypeAnnotations:
0: #15(): LOCAL_VARIABLE, {start_pc=2, length=15, index=2}
Signature: #17 // (TT;)V
public void doit(java.lang.Object);
descriptor: (Ljava/lang/Object;)V
flags: ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC
Code:
stack=2, locals=2, args_size=2
0: aload_0
1: aload_1
2: checkcast #4 // class java/lang/Runnable
5: invokevirtual #5 // Method doit:(Ljava/lang/Runnable;)V
8: return
RuntimeInvisibleTypeAnnotations:
0: #15(): LOCAL_VARIABLE, {start_pc=2, length=15, index=2}
}
Signature: #19 // <T::Ljava/lang/Runnable;>Ljava/lang/Object;LParameterizedInterface<TT;>;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
public class ClassWithBridgeMethod<T extends Runnable> implements ParameterizedInterface<T> {
@Override
public void doit(final T t) {
@TypeUseAnnotation
Object x = null;
// Some instructions just to widen the scope of annotation for x
System.out.println(x);
System.out.println(x);
}
}
interface ParameterizedInterface<T> {
void doit(T arg);
}
@Target({ ElementType.TYPE_USE })
@Retention(RetentionPolicy.CLASS)
@interface TypeUseAnnotation {
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment