Menu

#684 Single-file example for a lambda-related problem

v5.3.3
closed-fixed
None
9
2018-02-05
2018-01-26
corwin
No

I realize that some problems related to lambdas and obfuscation have been reported before (albeit a long time ago), but I have a super-simple example (one small file) that demonstrates the issue. This problem is currently blocking us from adopting a new build pipelline where the D8 compiler runs after ProGuard (as opposed to previous setup where retrolambda was used to handle lambdas prior to ProGuard pass, and where this problem did not appear) - hence a higher priority chosen.

For simplicity, I created a pure Java 8 (non-android) test case. I am attaching the relevant java file ProGuardFail.java) and the ProGuard configuration file (p_conf). Assuming you have the unpacked ProGuard distro in your home directory, you can reproduce the problem as follows (I am assuming 5.3.3 here, though the problem has been there at least since 5.2.1 and is also present in the newest beta):

javac -d . ProGuardFail.java
jar cvfe test.jar test.ProGuardFail test/*.class
~/proguard5.3.3/bin/proguard.sh @p_conf
java -jar test_out.jar

The real problem here seems to be interface indirection. If you use lambda as an argument to foo directly or if you have Factory.create method return ITest instead of SubITest, it will work as expected (print "7" rather than throw an error).

2 Attachments

Discussion

  • corwin

    corwin - 2018-01-27

    I looked at ProGuard's code and the fix is a one-liner, at least a fix that works for me. The question is of course whether it's generally applicable. I can't fine a way to submit a patch, though...

    The fix prevents obfuscation of all super-interfaces of the interface that is returned from invokedynamic (as opposed to prevent obfuscation of just the returned interface).

    Here's the patch against the current ProGuard repo tip, but it should be easily applicable to all versions):

    --- a/src/proguard/classfile/visitor/DynamicReturnedClassVisitor.java   Sun Apr 02 12:06:51 2017 +0200
    +++ b/src/proguard/classfile/visitor/DynamicReturnedClassVisitor.java   Fri Jan 26 17:20:21 2018 -0800
    @@ -61,7 +61,11 @@
                 Clazz referencedClass = referencedClasses[referencedClasses.length - 1];
                 if (referencedClass != null)
                 {
    
    -                referencedClass.accept(classVisitor);
    +                referencedClass.hierarchyAccept(true,
    +                                                false,
    +                                                true,
    +                                                false,
    +                                                classVisitor);
                 }
             }
         }
    
     
  • Eric Lafortune

    Eric Lafortune - 2018-01-28

    Thanks for the report and the fix. Essentially: empty extensions of functional interfaces are functional interfaces too. I've now fixed and refined the implementation (in the callers of this class) for the upcoming DexGuard 6.0 (beta3).

     
  • Eric Lafortune

    Eric Lafortune - 2018-01-28
    • status: open --> open-fixed
     
  • Eric Lafortune

    Eric Lafortune - 2018-02-05
    • Status: open-fixed --> closed-fixed
     

Log in to post a comment.

MongoDB Logo MongoDB