Analyzer produces frames that have different locals than those detected by JRE bytecode verifier
Issue was detected with class file instrumented by Quasar which uses ASM for instrumentation. QuasarInstrumentor instruments suspendable methods to preserve/restore Fiber stack. Analyzer.analyze()
is used to get Frame data based on which it determines variables that need to be pushed on the Fiber stack. However, bytecode verification of generated class fails with:
java.lang.VerifyError: Bad local variable type
Exception Details:
Location:
net/cordapp/utxo/apples/flows/pack/PackApplesFlow.call(Lnet/corda/v5/application/flows/ClientRequestBody;)Ljava/lang/String; @1508: iload
Reason:
Type top (current frame, locals[8]) is not assignable to integer
Current Frame:
bci: @1508
flags: { }
locals: { 'net/cordapp/utxo/apples/flows/pack/PackApplesFlow', 'net/corda/v5/application/flows/ClientRequestBody', 'net/corda/v5/membership/NotaryInfo', 'java/security/PublicKey', 'net/corda/v5/ledger/common/Party', 'net/corda/v5/ledger/common/Party', 'net/cordapp/utxo/apples/states/BasketOfApples', 'net/corda/v5/ledger/utxo/transaction/UtxoSignedTransaction', top, 'java/lang/Exception', top, top, top, 'co/paralleluniverse/fibers/suspend/StackOps', integer, null }
stack: { }
According to ASM Analyzer, local[8] is "I", while according to bytecode verifier it is "top".
Expected Behavior
Analyzer produces frames that have the same locals as detected by bytecode verifier.
Current Behavior
Analyzer produces frames that have different locals than detected by bytecode verifier which leads to VerifyError after instructions are added that handle such locals (in this case Quasar adds instructions that push all local variables on Fibre stack).
Steps to Reproduce
Provided generated class and unit tests that show the issue: asm.zip
- Test
loadingClassThrowsVerifyError
reproducesVerifyError
for generated class when class is verified by bytecode verifier. - Test
verifyingClassWithAsmDoesNotFindErrors
shows that ASM verifier doesn't find any issue with generated class. - Test
asmCalculatedFrameHasDifferentValue
shows that ASM produces frame which has local[8] set to "I", while bytecode verifier finds it's "top" (shown in error message fromloadingClassThrowsVerifyError
)