The old verifier tries to verified unreachable code

David Holmes david.holmes at oracle.com
Sun Aug 19 19:29:38 PDT 2012


Hi Keith,

On 20/08/2012 12:02 PM, Keith McGuigan wrote:
>
> Hi Rémi,
>
> Neither the old nor new verifier does any control-flow analysis to
> determine which parts of the bytecode are reachable; they both iterate
> over all the bytecodes (the old one potentially more than once) to
> ensure that the incoming and outgoing state of each bytecode is valid.

Hmmm. I don't think control flow analysis is needed here. The data-flow 
analysis that the JVMS describes would seem to preclude verification of 
unreachable code. You start by marking the "changed" bit of the first 
instruction of the method and proceed by finding all successor 
instructions to that one, marking those and repeating the process until 
no more instructions are marked as "changed". So in this case (assuming 
the goto goes to the return) we start by marking the goto, the only 
successor is the return and it has no successor in this method. Hence 
the astore would never be verified.

That said I'm not 100% sure that JVMS 4.9.2 was meant be to prescriptive 
rather than just descriptive.

David
-----

> So throwing a verifier error in this situation is expected, and is, I
> believe, required by the Java Virtual Machine Specification.
>
> --
> - Keith
>
> On 8/19/2012 10:00 AM, Rémi Forax wrote:
>> Hi guys,
>> I suppose that the bytecode verifier belong to this list,
>> the following code while stupid should in my opinion be a valid bytecode
>> given that the bytecode at 3 is not reachable
>>
>> public void foo()
>> Code:
>> Stack=0, Locals=2, Args_size=1
>> 0: goto 6
>> 3: astore_1
>> 4: return
>> Exception table:
>> from to target type
>> 3 4 3 any
>>
>> but it seems that the old verifier requires the stack to be at least 1
>> even if
>> the exception handler is never reachable.
>>
>> Here is a simple code using ASM to reproduce the bug.
>>
>> public static void main(String[] args) {
>> ClassWriter writer = new ClassWriter(0);
>> writer.visit(V1_5, ACC_PUBLIC|ACC_SUPER, "Foo", null,
>> "java/lang/Object", null);
>> MethodVisitor mv = writer.visitMethod(ACC_PUBLIC, "foo", "()V",
>> null, null);
>> mv.visitCode();
>>
>> Label start = new Label();
>> Label end = new Label();
>> Label handler = new Label();
>> mv.visitTryCatchBlock(start, end, handler, null);
>>
>> Label label = new Label();
>> mv.visitJumpInsn(GOTO, label);
>>
>> mv.visitLabel(handler);
>> mv.visitLabel(start);
>> mv.visitVarInsn(ASTORE, 1);
>> mv.visitLabel(end);
>>
>> mv.visitLabel(label);
>> mv.visitInsn(RETURN);
>>
>> mv.visitMaxs(0, 2);
>> mv.visitEnd();
>> writer.visitEnd();
>>
>> final byte[] byteArray = writer.toByteArray();
>> Class<?> clazz = new ClassLoader() {
>> Class<?> def() {
>> return defineClass("Foo", byteArray, 0, byteArray.length);
>> }
>> }.def();
>>
>> clazz.getDeclaredMethods();
>> }
>>
>> cheers,
>> Rémi
>>


More information about the hotspot-runtime-dev mailing list