-
Bug
-
Resolution: Unresolved
-
P3
-
None
-
24, 25, 26
-
None
A valid method *) was converted into an equivalent piece of ClassFile API code **) for testing purposes.
*)
public static int run(int i) {
try {
if (i < 0) {
throw new IllegalArgumentException();
}
throw new IndexOutOfBoundsException();
} catch (IllegalArgumentException e) {
return 0;
} catch (Exception e) {
return 1000;
}
}
**)
mb.withCode(cb -> {
cb.trying(
tb -> {
tb.block(bb -> {
bb.iload(0);
bb.branch(Opcode.IFGE, bb.endLabel()); // ifge L12
bb.new_(CD_IAE);
bb.dup();
bb.invokespecial(CD_IAE, "<init>", MTD_void);
bb.athrow();
});
tb.block(bb -> {
bb.new_(CD_IOBE);
bb.dup();
bb.invokespecial(CD_IOBE, "<init>", MTD_void);
bb.athrow();
});
// 20: {opcode: GOTO, target: 31} added by the ClassFile API
// "31" exceeds the end of the Code attribute.
// can be fixed by adding tb.return_();
},
catchBuilder -> {
catchBuilder.catching(CD_IAE, bb -> {
bb.aload(1); // astore_1
bb.iconst_0(); // iconst_0
bb.ireturn(); // ireturn
});
catchBuilder.catching(CD_E, bb -> {
bb.aload(1); // astore_1
bb.sipush(1000); // sipush 1000
bb.ireturn(); // ireturn
});
}
);
});
Then, building the classfile bytes throws the following exception:
java.lang.IllegalArgumentException: Detected branch target out of bytecode range at bytecode offset 20 of method run(int)
— max stack: 65535
— max locals: 65535
— attributes: []
// stack map frame @0: {locals: [int], stack: []}
0: {opcode: ILOAD_0, slot: 0}
1: {opcode: IFGE, target: 12}
4: {opcode: NEW, type: java/lang/IllegalArgumentException}
7: {opcode: DUP}
8: {opcode: INVOKESPECIAL, owner: java/lang/IllegalArgumentException, method name: <init>, method type: ()V}
11: {opcode: ATHROW}
12: {opcode: NEW, type: java/lang/IndexOutOfBoundsException}
15: {opcode: DUP}
16: {opcode: INVOKESPECIAL, owner: java/lang/IndexOutOfBoundsException, method name: <init>, method type: ()V}
19: {opcode: ATHROW}
20: {opcode: GOTO, target: 31}
23: {opcode: ALOAD_1, slot: 1}
24: {opcode: ICONST_0, constant value: 0}
25: {opcode: IRETURN}
26: {opcode: ALOAD_1, slot: 1}
27: {opcode: SIPUSH, constant value: 1000}
30: {opcode: IRETURN}
As can be seen, the instruction at offset 20: {opcode: GOTO, target: 31} was added to the output. This instruction jumps beyond the valid code range.
An example of the code is attached.
*)
public static int run(int i) {
try {
if (i < 0) {
throw new IllegalArgumentException();
}
throw new IndexOutOfBoundsException();
} catch (IllegalArgumentException e) {
return 0;
} catch (Exception e) {
return 1000;
}
}
**)
mb.withCode(cb -> {
cb.trying(
tb -> {
tb.block(bb -> {
bb.iload(0);
bb.branch(Opcode.IFGE, bb.endLabel()); // ifge L12
bb.new_(CD_IAE);
bb.dup();
bb.invokespecial(CD_IAE, "<init>", MTD_void);
bb.athrow();
});
tb.block(bb -> {
bb.new_(CD_IOBE);
bb.dup();
bb.invokespecial(CD_IOBE, "<init>", MTD_void);
bb.athrow();
});
// 20: {opcode: GOTO, target: 31} added by the ClassFile API
// "31" exceeds the end of the Code attribute.
// can be fixed by adding tb.return_();
},
catchBuilder -> {
catchBuilder.catching(CD_IAE, bb -> {
bb.aload(1); // astore_1
bb.iconst_0(); // iconst_0
bb.ireturn(); // ireturn
});
catchBuilder.catching(CD_E, bb -> {
bb.aload(1); // astore_1
bb.sipush(1000); // sipush 1000
bb.ireturn(); // ireturn
});
}
);
});
Then, building the classfile bytes throws the following exception:
java.lang.IllegalArgumentException: Detected branch target out of bytecode range at bytecode offset 20 of method run(int)
— max stack: 65535
— max locals: 65535
— attributes: []
// stack map frame @0: {locals: [int], stack: []}
0: {opcode: ILOAD_0, slot: 0}
1: {opcode: IFGE, target: 12}
4: {opcode: NEW, type: java/lang/IllegalArgumentException}
7: {opcode: DUP}
8: {opcode: INVOKESPECIAL, owner: java/lang/IllegalArgumentException, method name: <init>, method type: ()V}
11: {opcode: ATHROW}
12: {opcode: NEW, type: java/lang/IndexOutOfBoundsException}
15: {opcode: DUP}
16: {opcode: INVOKESPECIAL, owner: java/lang/IndexOutOfBoundsException, method name: <init>, method type: ()V}
19: {opcode: ATHROW}
20: {opcode: GOTO, target: 31}
23: {opcode: ALOAD_1, slot: 1}
24: {opcode: ICONST_0, constant value: 0}
25: {opcode: IRETURN}
26: {opcode: ALOAD_1, slot: 1}
27: {opcode: SIPUSH, constant value: 1000}
30: {opcode: IRETURN}
As can be seen, the instruction at offset 20: {opcode: GOTO, target: 31} was added to the output. This instruction jumps beyond the valid code range.
An example of the code is attached.