Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bytecode retains seemingly pointless checkcast instruction causing VerifyError #460

Open
JakeWharton opened this issue Jan 7, 2025 · 2 comments

Comments

@JakeWharton
Copy link

JakeWharton commented Jan 7, 2025

I'm attempting to run ProGuard 7.6.1 on my library's unit tests to assert they all still pass when the library is minified. My library depends on kotlinx.coroutines which contains code that ProGuard processes into an invalid state causing a VerifyError:

java.lang.VerifyError: Bad type on operand stack
Exception Details:
  Location:
    kotlinx/coroutines/JobKt.invokeOnCompletion(Lkotlinx/coroutines/Job;ZLkotlinx/coroutines/JobNode;)Lkotlinx/coroutines/DisposableHandle; @40: invokeinterface
  Reason:
    Type 'kotlin/jvm/functions/Function1' (current frame, stack[3]) is not assignable to 'kotlinx/coroutines/JobKt__JobKt$invokeOnCompletion$1'
  Current Frame:
    bci: @40
    flags: { }
    locals: { 'kotlinx/coroutines/Job', integer, 'kotlinx/coroutines/JobNode' }
    stack: { 'kotlinx/coroutines/Job', integer, integer, 'kotlin/jvm/functions/Function1' }
  Bytecode:
    0000000: 2a1b 2c4d 3c59 4bc1 0007 9900 0d2a c000
    0000010: 071b 2cb6 000a b02a 2cb6 0009 1bbb 0005
    0000020: 592c b700 08c0 0002 b900 0b04 00b0
  Stackmap Table:
    same_frame(@23)

    at kotlinx.coroutines.JobKt__JobKt.invokeOnCompletion$default$7beb268f(Job.kt:351)
    at kotlinx.coroutines.CancellableContinuationImpl.installParentHandle(CancellableContinuationImpl.kt:23001)
    at kotlinx.coroutines.CancellableContinuationImpl.initCancellability(CancellableContinuationImpl.kt:126)
    at kotlinx.coroutines.DelayKt.delay-VtjQ1oo(Delay.kt:2178)

The offending bytecode is this:

29: new           #5                  // class kotlinx/coroutines/JobKt__JobKt$invokeOnCompletion$1
32: dup
33: aload_2
34: invokespecial #8                  // Method kotlinx/coroutines/JobKt__JobKt$invokeOnCompletion$1."<init>":(Lkotlinx/coroutines/JobNode;)V
37: checkcast     #2                  // class kotlin/jvm/functions/Function1
40: invokeinterface #11,  4           // InterfaceMethod kotlinx/coroutines/Job.invokeOnCompletion$87b5a68:(ZZLkotlinx/coroutines/JobKt__JobKt$invokeOnCompletion$1;)Lkotlinx/coroutines/DisposableHandle;

Here we can see that the offending bytecode 40 is an invoke which accepts a type of kotlinx/coroutines/JobKt__JobKt$invokeOnCompletion$1 but the bytecode prior, 37, is doing a cast to kotlin/jvm/functions/Function1 which causes the error:

Type 'kotlin/jvm/functions/Function1' (current frame, stack[3]) is not assignable to 'kotlinx/coroutines/JobKt__JobKt$invokeOnCompletion$1'

The original function in kotlinx.coroutines uses the Function1 type for its parameter, and the anonymous $1 class does implement that interface. ProGuard seems to be lifting the parameter type to the sole implementation the method is invoked with, but failing to remove the now-needless and error-inducing checkcast.

A PR with the offending build setup is here: JakeWharton/mosaic#591

If this is too difficult to run to debug in its current state (Gradle's build classpath), I'm happy to create an isolated project that reproduces.

@piazzesiNiccolo-GS
Copy link
Contributor

piazzesiNiccolo-GS commented Jan 8, 2025

Thanks for the report!

I was able to patch your PR and reproduce the issue locally. It indeed seems to be caused by the method/specialization/parametertype optimization not detecting the check cast right before that. If you need to unblock your pr, you can temporarily disable only that optimization with this rule:

-optimizations !method/specialization/parametertype

It solves the issue locally for me. Looking at what's going wrong, it seems we don't handle such cases in the MemberDescriptorSpecializer

@JakeWharton
Copy link
Author

Thanks! I'll use that workaround for now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants