-
Bug
-
Resolution: Unresolved
-
P4
-
None
-
25
-
generic
-
generic
ADDITIONAL SYSTEM INFORMATION :
java version "25" 2025-09-16 LTS
Java(TM) SE Runtime Environment (build 25+37-LTS-3491)
Java HotSpot(TM) 64-Bit Server VM (build 25+37-LTS-3491, mixed mode, sharing)
A DESCRIPTION OF THE PROBLEM :
When using the Java java.lang.classfile API to construct and parse class files that contain branch instructions (such as ifge with labels), a bug surfaces in which the labels (used as branch targets) may remain uninflated after parsing with ClassFile.of().parse(byteCode). As a result, any subsequent processing or copying of the parsed CodeModel such as emitting a new class file using with(cde) can trigger the following error:
---------- BEGIN SOURCE ----------
import java.lang.classfile.*;
import java.lang.constant.*;
class ClassFileBug {
public static void main(String[] args) {
// (1) Build a trivial class with a branch:
// equivalent to:
// class TestClass {
// static int clamp(int x) {
// if (x < 0) return 0;
// return x;
// }
// }
ClassDesc className = ClassDesc.of("TestClass");
String methodName = "clamp";
MethodTypeDesc methodType = MethodTypeDesc.of(ConstantDescs.CD_int, ConstantDescs.CD_int);
int methodFlags = ClassFile.ACC_STATIC;
byte[] byteCode = ClassFile.of(ClassFile.StackMapsOption.DROP_STACK_MAPS).build(className, clb -> {
clb.withMethodBody(methodName, methodType, methodFlags, cdb -> {
var label = cdb.newLabel();
// if (x < 0)
cdb.iload(0);
cdb.ifge(label);
// return 0
cdb.iconst_0();
cdb.ireturn();
// return x
cdb.labelBinding(label);
cdb.iload(0);
cdb.ireturn();
});
});
// (2) Load the CodeModel back in
ClassModel classModel = ClassFile.of().parse(byteCode);
CodeModel methodCode = classModel.methods().getFirst().code().get();
// (3) Try to use the code in a new class; it blows up:
// "Detected branch target out of bytecode range at bytecode offset 1 of method clamp(int)
// 0000: 1a 9c ff fe 03 ac 1a ac"
ClassFile.of().build(className, clb -> {
clb.withMethodBody(methodName, methodType, methodFlags, cdb -> {
//methodCode.toDebugString(); // ##### <-- uncomment this line and the exception disappears #####
for (CodeElement cde : methodCode) {
cdb.with(cde);
}
});
});
System.out.println("Success");
}
}
---------- END SOURCE ----------
This issue does not occur if the debugging method toDebugString() is called on the CodeModel before reuse, suggesting that the process of inflating labels is incorrectly deferred until such a call.
java version "25" 2025-09-16 LTS
Java(TM) SE Runtime Environment (build 25+37-LTS-3491)
Java HotSpot(TM) 64-Bit Server VM (build 25+37-LTS-3491, mixed mode, sharing)
A DESCRIPTION OF THE PROBLEM :
When using the Java java.lang.classfile API to construct and parse class files that contain branch instructions (such as ifge with labels), a bug surfaces in which the labels (used as branch targets) may remain uninflated after parsing with ClassFile.of().parse(byteCode). As a result, any subsequent processing or copying of the parsed CodeModel such as emitting a new class file using with(cde) can trigger the following error:
---------- BEGIN SOURCE ----------
import java.lang.classfile.*;
import java.lang.constant.*;
class ClassFileBug {
public static void main(String[] args) {
// (1) Build a trivial class with a branch:
// equivalent to:
// class TestClass {
// static int clamp(int x) {
// if (x < 0) return 0;
// return x;
// }
// }
ClassDesc className = ClassDesc.of("TestClass");
String methodName = "clamp";
MethodTypeDesc methodType = MethodTypeDesc.of(ConstantDescs.CD_int, ConstantDescs.CD_int);
int methodFlags = ClassFile.ACC_STATIC;
byte[] byteCode = ClassFile.of(ClassFile.StackMapsOption.DROP_STACK_MAPS).build(className, clb -> {
clb.withMethodBody(methodName, methodType, methodFlags, cdb -> {
var label = cdb.newLabel();
// if (x < 0)
cdb.iload(0);
cdb.ifge(label);
// return 0
cdb.iconst_0();
cdb.ireturn();
// return x
cdb.labelBinding(label);
cdb.iload(0);
cdb.ireturn();
});
});
// (2) Load the CodeModel back in
ClassModel classModel = ClassFile.of().parse(byteCode);
CodeModel methodCode = classModel.methods().getFirst().code().get();
// (3) Try to use the code in a new class; it blows up:
// "Detected branch target out of bytecode range at bytecode offset 1 of method clamp(int)
// 0000: 1a 9c ff fe 03 ac 1a ac"
ClassFile.of().build(className, clb -> {
clb.withMethodBody(methodName, methodType, methodFlags, cdb -> {
//methodCode.toDebugString(); // ##### <-- uncomment this line and the exception disappears #####
for (CodeElement cde : methodCode) {
cdb.with(cde);
}
});
});
System.out.println("Success");
}
}
---------- END SOURCE ----------
This issue does not occur if the debugging method toDebugString() is called on the CodeModel before reuse, suggesting that the process of inflating labels is incorrectly deferred until such a call.