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