Re: NegativeArraySizeException merging frames during replaceAsmInstructions

"ebruneton" (via asm Mailing List) <[email protected]> Thu, 17 Mar 2022 16:33:53 +0100
Newsgroups gmane.comp.java.objectweb.asm
Message-ID <[email protected]>
This is a multi-part message in MIME format...

------------=_1647531237-25320-12
Content-Type: text/plain; charset=UTF-8;
 format=flowed
Content-Transfer-Encoding: 8bit

Le 17/03/2022 16:15, Eirik Bjørsnøs a écrit :
> Eric,
> 
> Thanks a lot for your patience :-)
> 
> I finally figured out that I did indeed have one branch target which
> was missing a frame. The reason I thought I didn't was that the
> particular class being instrumented was a Java 6 class, so frames are
> not strictly required by the JVM.

If your class is a Java 6 class but contains frames before 
instrumentation, another solution might be to remove all the frames as 
part of the instrumentation (and to not add any for your new branch 
targets).

> Eirik.
> 
> On Thu, Mar 17, 2022 at 2:32 PM <[email protected]> wrote:
> 
>> Le 17/03/2022 12:50, Eirik Bjørsnøs a écrit :
>>> Eric,
>>> 
>>> When I add a frame before the exception handler, the NASE
>> magically no
>>> longer occurs.
>>> 
>>> My "real" instrumentation uses a custom AdviceAdapter which does
>> not
>>> extend LocalVariablesSorter and thus does not require expanded
>> frames.
>> 
>> Even if you don't need EXPAND_FRAMES, if your instrumentation
>> changes
>> the control flow (e.g. with new if or goto statements, or with try
>> catch
>> blocks) you still need to update or insert new frames accordingly
>> (either manually or with COMPUTE_FRAMES).
>> 
>>> This will make it a bit harder to make a simple reproducer that
>> shows
>>> the real problem, but I'll give it a go :-)
>>> 
>>> Eirik.
>>> 
>>> On Thu, Mar 17, 2022 at 11:40 AM <[email protected]> wrote:
>>> 
>>>> Hi,
>>>> 
>>>> The issue is that your instrumentation changes the control flow
>> of a
>>>> 
>>>> method, with the addition of a try catch block, but the
>> ClassWriter
>>>> only
>>>> has a COMPUTE_MAXS option. As a result, frames are not
>> recomputed,
>>>> and
>>>> there is a missing frame just before the exception handler. To
>> fix
>>>> this
>>>> you can either use COMPUTE_FRAMES instead of COMPUTE_MAXS, or
>>>> manually
>>>> compute and insert the missing frame before the ATHROW with a
>>>> vistFrame(...).
>>>> 
>>>> Eric
>>>> 
>>>> PS: in your TryCatchWrapper, it is better to visit the try catch
>>>> block
>>>> before its labels, as follows (and as documented in
>> MethodVisitor):
>>>> 
>>>> private static class TryCatchWrapper extends AdviceAdapter {
>>>> 
>>>> private Label start;
>>>> private Label end;
>>>> 
>>>> public TryCatchWrapper(MethodVisitor mv, int access, String
>>>> 
>>>> name, String descriptor) {
>>>> super(ASM9, mv, access, name, descriptor);
>>>> }
>>>> 
>>>> @Override
>>>> protected void onMethodEnter() {
>>>> start = new Label();
>>>> end = new Label();
>>>> visitTryCatchBlock(start, end, end, null);
>>>> mv.visitLabel(start);
>>>> }
>>>> 
>>>> @Override
>>>> public void visitMaxs(int maxStack, int maxLocals) {
>>>> visitLabel(end);
>>>> visitInsn(ATHROW);
>>>> super.visitMaxs(maxStack, maxLocals);
>>>> }
>>>> }
>>>> 
>>>> Le 16/03/2022 20:59, Eirik Bjørsnøs a écrit :
>>>>> Hi,
>>>>> 
>>>>> I'm observing a NASE during toByteArray/replaceAsmInstructions
>>>> while
>>>>> instrumenting byte code in a Java agent I'm working on.
>>>>> 
>>>>> I have been able to create a standalone reproducer [1] which
>>>> provokes
>>>>> the following conditions:
>>>>> 
>>>>> 1: One of the methods in the class should incude a Label which
>>>> returns
>>>>> false from the Label.resolve method. This is because the label
>> is
>>>> a
>>>>> forward reference with a relative offset larger than
>>>> Short.MAX_VALUE,
>>>>> hence ASMs hasAsmInstructions is set to true. This seems
>> necessary
>>>> to
>>>>> force a call to replaceAsmInstructions which triggers frame
>>>>> processing.
>>>>> 
>>>>> 2: Another method of the class is instrumented with a
>>>> trycatchblock
>>>>> which wraps the body of the method This catch block handler
>> simply
>>>>> ATHROWs the Throwable. This seems necessary to create the
>>>> conditions
>>>>> where the frame merge throws NASE.
>>>>> 
>>>>> Here's the stack trace cased by the minimal reproducer:
>>>>> 
>>>>> Exception in thread "main" java.lang.NegativeArraySizeException:
>>>> -1
>>>>> at org.objectweb.asm.Frame.merge(Frame.java:1222)
>>>>> at org.objectweb.asm.CurrentFrame.execute(CurrentFrame.java:53)
>>>>> at
>> org.objectweb.asm.MethodWriter.visitInsn(MethodWriter.java:868)
>>>>> at org.objectweb.asm.ClassReader.readCode(ClassReader.java:2213)
>>>>> at
>> org.objectweb.asm.ClassReader.readMethod(ClassReader.java:1514)
>>>>> at org.objectweb.asm.ClassReader.accept(ClassReader.java:744)
>>>>> at
>>>>> 
>>>> 
>>> 
>> 
> org.objectweb.asm.ClassWriter.replaceAsmInstructions(ClassWriter.java:755)
>>>>> at
>> org.objectweb.asm.ClassWriter.toByteArray(ClassWriter.java:718)
>>>>> at
>>>>> 
>>>> 
>>> 
>> 
> com.example.asmnase.ReplaceAsmInstructionsNASE.main(ReplaceAsmInstructionsNASE.java:37)
>>>>> 
>>>>> The following Gist contains the reproducer:
>>>>> 
>>>>> https://gist.github.com/eirbjo/3eb8ca755f2a399ac8e5def6f43439e5
>>>>> 
>>>>> Note that the instrumentation produces valid class files which
>> are
>>>>> verified and loaded by the JVM. It's only in the abnormal case
>> of
>>>>> large relative forward references that ASM throws this
>> exception.
>>>> So I
>>>>> think the produced byte code is valid and there might be a bug
>> in
>>>> ASM
>>>>> here.
>>>>> 
>>>>> What do you think?
>>>>> 
>>>>> Cheers,
>>>>> Eirik.
>>>>> 
>>>>> --
>>>>> You receive this message as a subscriber of the [email protected]
>>>> mailing
>>>>> list.
>>>>> To unsubscribe: mailto:[email protected]
>>>>> For general help: mailto:[email protected]?subject=help
>>>>> OW2 mailing lists service home page: http://www.ow2.org/wws

------------=_1647531237-25320-12
Content-Type: text/plain; charset="UTF-8"
Content-Disposition: inline
Content-Transfer-Encoding: 8bit


-- 
You receive this message as a subscriber of the [email protected] mailing list.
To unsubscribe: mailto:[email protected]
For general help: mailto:[email protected]?subject=help
OW2 mailing lists service home page: http://www.ow2.org/wws

------------=_1647531237-25320-12--