Asymmetry of ClassWriter for bytecode versions higher than the one that ClassReader accepts
With ASM 6.0 and ASM 6.1-beta
private static void fun(int count) {
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
cw.visit(Opcodes.V9 + 2, 0, "Example", null, null, null);
MethodVisitor mv = cw.visitMethod(0, "fun", "()V", null, null);
mv.visitCode();
mv.visitInsn(Opcodes.ICONST_0);
final Label target = new Label();
mv.visitJumpInsn(Opcodes.IFLE, target);
for (int i = 0; i < count; i++) {
mv.visitInsn(Opcodes.NOP);
}
mv.visitLabel(target);
mv.visitInsn(Opcodes.RETURN);
mv.visitMaxs(0, 0);
mv.visitEnd();
cw.visitEnd();
cw.toByteArray();
}
invocation of
fun(Short.MAX_VALUE - 2);
will throw
Exception in thread "main" java.lang.IllegalArgumentException
at org.objectweb.asm.ClassReader.<init>(ClassReader.java:149)
at org.objectweb.asm.ClassReader.<init>(ClassReader.java:133)
at org.objectweb.asm.ClassWriter.toByteArray(ClassWriter.java:615)
whereas invocation of
fun(Short.MAX_VALUE - 3);
won't.
This asymmetry is hard to spot and one could think that ClassWriter
can be safely used to generate class files with version higher than the one that ClassReader
accepts, which is clearly not always the case.
For the record this was accidentally discovered (went almost unnoticed) during attempt to follow suggestion from https://github.com/gradle/gradle/issues/3770#issuecomment-354871334 about patching bytecode back and forth to bypass check in ClassReader
.