Proguard obfuscation of Java8 method references breaks at runtime

前端 未结 1 1639
粉色の甜心
粉色の甜心 2021-01-14 18:02

I am encountering a persistent problem when obfuscating java8 source code. Lambda method references seem to fail at runtime when they are used multiple times within a functi

相关标签:
1条回答
  • 2021-01-14 18:42

    In the original BootstrapMethods attribute

    BootstrapMethods:
        0: #141 invokestatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
          Method arguments:
            #142 (Ljava/lang/Object;)Ljava/lang/Object;
            #143 invokevirtual package/db/dto/RoleDTO.getName:()Ljava/lang/String;
            #144 (Lpackage/db/dto/RoleDTO;)Ljava/lang/String;
        1: #141 invokestatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
          Method arguments:
            #142 (Ljava/lang/Object;)Ljava/lang/Object;
            #155 invokevirtual package/db/dto/NameDescriptionDTO.getName:()Ljava/lang/String;
            #156 (Lpackage/db/dto/PermissionDTO;)Ljava/lang/String;
    

    both entries point to different target methods. You see clearly #143 invokevirtual … RoleDTO.getName and #155 invokevirtual … NameDescriptionDTO.getName; these two arguments correspond to the implMethod parameter of the bootstrap method

    metafactory(caller, invokedName, invokedType, samMethodType, implMethod, instantiatedMethodType)

    In contrast, in the obfuscated class’ BootstrapMethods attribute

      BootstrapMethods:
        0: #63 invokestatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
          Method arguments:
            #93 (Ljava/lang/Object;)Ljava/lang/Object;
            #62 invokevirtual package/db/dto/RoleDTO.getName:()Ljava/lang/String;
            #95 (Lpackage/db/dto/RoleDTO;)Ljava/lang/String;
        1: #63 invokestatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
          Method arguments:
            #93 (Ljava/lang/Object;)Ljava/lang/Object;
            #62 invokevirtual package/db/dto/RoleDTO.getName:()Ljava/lang/String;
            #94 (Lpackage/db/dto/PermissionDTO;)Ljava/lang/String;
    

    both entries refer to exactly the same target method #62 invokevirtual … RoleDTO.getName.

    So the obfuscator made a semantic changing transformation here, I guess it’s a bug in Proguard. The JRE is correct in rejecting the call as the last entry still requests the functional signature (PermissionDTO)String but wants to link it to the target method RoleDTO.getName which has the functional signature (RoleDTO)String and PermissionDTO can’t be assigned to RoleDTO (that’s exactly what the message says).

    0 讨论(0)
提交回复
热议问题