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

java.lang.VerifyError: Bad type on operand stack for Kotlin 2.0 and KotlinX Serialization #415

Open
shanshin opened this issue Jun 25, 2024 · 1 comment

Comments

@shanshin
Copy link

The Kotlin code compiled by Kotlin 2.0 with KotlinX serialization applied is executed with an error if ProGuard optimization is enabled.

Error

Exception in thread "main" java.lang.VerifyError: Bad type on operand stack
Exception Details:
  Location:
    dev/mikchan/misc/ksp/model/Model$$serializer.<clinit>()V @38: putstatic
  Reason:
    Type 'dev/mikchan/misc/ksp/shadow/kotlinx/serialization/descriptors/SerialDescriptor' (current frame, stack[0]) is not assignable to 'dev/mikchan/misc/ksp/shadow/kotlinx/serialization/internal/PluginGeneratedSerialDescriptor'
  Current Frame:
    bci: @38
    flags: { }
    locals: { 'dev/mikchan/misc/ksp/shadow/kotlinx/serialization/internal/PluginGeneratedSerialDescriptor' }
    stack: { 'dev/mikchan/misc/ksp/shadow/kotlinx/serialization/descriptors/SerialDescriptor' }

Reproducer

Reproducer project: https://github.com/wtlgo/Kotlin-Serialization-Proguard

To reproduce:

  • call proguardJar Gradle task
  • launch application java -jar build/libs/Kotlin-Serialization-Proguard-1.0-SNAPSHOT-pro.jar

Details

As an example, we can consider the class dev.mikchan.misc.ksp.model.Model$$serializer

The problem is in the <clinit> method

Original method bytecode

  static {};
    descriptor: ()V
    flags: (0x0008) ACC_STATIC
    Code:
      stack=5, locals=1, args_size=0
         0: new           #2                  // class dev/mikchan/misc/ksp/model/Model$$serializer
         3: dup
         4: invokespecial #144                // Method "<init>":()V
         7: putstatic     #146                // Field INSTANCE:Ldev/mikchan/misc/ksp/model/Model$$serializer;
        10: new           #148                // class dev/mikchan/misc/ksp/shadow/kotlinx/serialization/internal/PluginGeneratedSerialDescriptor
        13: dup
        14: ldc           #150                // String dev.mikchan.misc.ksp.model.Model
        16: getstatic     #146                // Field INSTANCE:Ldev/mikchan/misc/ksp/model/Model$$serializer;
        19: checkcast     #7                  // class dev/mikchan/misc/ksp/shadow/kotlinx/serialization/internal/GeneratedSerializer
        22: iconst_1
        23: invokespecial #153                // Method dev/mikchan/misc/ksp/shadow/kotlinx/serialization/internal/PluginGeneratedSerialDescriptor."<init>":(Ljava/lang/String;Ldev/mikchan/misc/ksp/shadow/kotlinx/serialization/internal/GeneratedSerializer;I)V
        26: astore_0
        27: aload_0
        28: ldc           #155                // String lets
        30: iconst_0
        31: invokevirtual #159                // Method dev/mikchan/misc/ksp/shadow/kotlinx/serialization/internal/PluginGeneratedSerialDescriptor.addElement:(Ljava/lang/String;Z)V
        34: aload_0
        35: checkcast     #113                // class dev/mikchan/misc/ksp/shadow/kotlinx/serialization/descriptors/SerialDescriptor
        38: putstatic     #73                 // Field descriptor:Ldev/mikchan/misc/ksp/shadow/kotlinx/serialization/descriptors/SerialDescriptor;
        41: return
      LineNumberTable:
        line 5: 10
        line 6: 41
}

optimyzed bytecode

  static {};
    descriptor: ()V
    flags: (0x0008) ACC_STATIC
    Code:
      stack=5, locals=1, args_size=0
         0: new           #7                  // class dev/mikchan/misc/ksp/model/Model$$serializer
         3: dup
         4: invokespecial #24                 // Method "<init>":()V
         7: putstatic     #20                 // Field INSTANCE:Ldev/mikchan/misc/ksp/model/Model$$serializer;
        10: new           #16                 // class dev/mikchan/misc/ksp/shadow/kotlinx/serialization/internal/PluginGeneratedSerialDescriptor
        13: dup
        14: ldc           #2                  // String dev.mikchan.misc.ksp.model.Model
        16: getstatic     #20                 // Field INSTANCE:Ldev/mikchan/misc/ksp/model/Model$$serializer;
        19: checkcast     #15                 // class dev/mikchan/misc/ksp/shadow/kotlinx/serialization/internal/GeneratedSerializer
        22: iconst_1
        23: invokespecial #27                 // Method dev/mikchan/misc/ksp/shadow/kotlinx/serialization/internal/PluginGeneratedSerialDescriptor."<init>":(Ljava/lang/String;Ldev/mikchan/misc/ksp/shadow/kotlinx/serialization/internal/GeneratedSerializer;I)V
        26: dup
        27: astore_0
        28: ldc           #3                  // String lets
        30: iconst_0
        31: invokevirtual #28                 // Method dev/mikchan/misc/ksp/shadow/kotlinx/serialization/internal/PluginGeneratedSerialDescriptor.addElement:(Ljava/lang/String;Z)V
        34: aload_0
        35: checkcast     #12                 // class dev/mikchan/misc/ksp/shadow/kotlinx/serialization/descriptors/SerialDescriptor
        38: putstatic     #21                 // Field descriptor$2e3cfc03:Ldev/mikchan/misc/ksp/shadow/kotlinx/serialization/internal/PluginGeneratedSerialDescriptor;
        41: return
      LineNumberTable:
        line 5: 10
        line 6: 41
}

As you can see, the type of the descriptor field has changed from Ldev/mikchan/misc/ksp/shadow/kotlinx/serialization/descriptors/SerialDescriptor; to Ldev/mikchan/misc/ksp/shadow/kotlinx/serialization/internal/PluginGeneratedSerialDescriptor;

The problem goes away if you add the rule

-keepclassmembers public class **$$serializer {
    private ** descriptor;
}
@wtlgo
Copy link

wtlgo commented Jun 28, 2024

I've removed my repository, but here's a here's a zip of it. I wasn't aware it was referenced here when I did it, I'm sorry.

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