5

After an update of Dexguard from 7.0.12 to 7.1.22, I'm encountering a crash on an Enum switch.

This only happens when Dexguard has run on our project (I suppose this is caused by a Proguard issue).

If I use hardcoded values, the crash does not occur.

Ofcourse, I want to avoid using hardcoded values.

THE CRASH

The crash that occurs is the following

java.lang.NoClassDefFoundError: Failed resolution of: Lif;

This occurs on the line that states switch(type) { (see below)

EXAMPLE

Some example code on which the app crashes (given that MyEnum is an Enum ofcourse):

MyEnum type = MyEnum.SomeValue;

switch (type) {
    case SomeValue:
        // Do something
        Log.i("Tag", "Hello world!");
        break;
}

Assume that the ordinal value of MyEnum.SomeValue is 1.

If I change case SomeValue: to case 1: it works like expected.

WHAT I HAVE TRIED

I do not know why this crash occurs. I have tried to add these Proguard rules.

-keep enum * { *; }
-keepclassmembers enum * {
    public static **[] values();
    public static ** valueOf(java.lang.String);
}

But this does not fix the issue.

UPDATE

I just checked the mapping file, all of my enum names etc are kept. Now I'm even more clueless of what's happening.

my.identifier.MyEnum -> my.identifier.MyEnum:
    my.identifier.MyEnum SomeValue -> SomeValue
    my.identifier.MyEnum[] $VALUES -> $VALUES
    6:6:my.identifier.MyEnum[] values() -> values
    6:6:my.identifier.MyEnum valueOf(java.lang.String) -> valueOf
    6:6:void <init>(java.lang.String,int) -> <init>
    6:7:void <clinit>() -> <clinit>

UPDATE 2

Just took a look at the output. It's compiled to this. Judging on the stack trace, I suppose if is not kept by Proguard. Where is this defined? what do I need to add to make Proguard keep this?

switch(if.ˊ[var2.ordinal()]) {
    case 1:
        //some other code
        break;

UPDATE 3

In the intermediates that line of code looks like this:

switch(null.$SwitchMap$my$identifier$MyEnum[type.ordinal()]) {
    case 1:
        //some other code
        break;

the fact that it states null.$ bothers me. That does not seem right. or is that normal?

UPDATE 4

Just reverted to our older version of Dexguard and removed the Proguard rules I added.

The crash does not occur anymore now, although the code still looks exactly the same. (The intermediates AND the fully compiled code)

Update 5

Switched over to Dexguard 7.2 and it went flawless.

SnyersK
  • 1,296
  • 8
  • 23
  • Can you contact support@guardsquare.com with this problem, including your configuration files and apk for further investigation? – T. Neidhart Jun 09 '16 at 10:06
  • I just came across the same issue when packaging up my app in Google's: Android App Bundle - AAB after downloading my app from Google Play. The annoying part is: I didn't even enable ProGuard. – TomDK Jul 04 '19 at 06:47

2 Answers2

1

The switch statement will create a synthetic inner class with an array field $SwitchMap$MyEnum mapping the ordinal of the enum field to an integer greater than 0. You need to make sure this class and it field are preserved as well.

tynn
  • 38,113
  • 8
  • 108
  • 143
  • How can I do or check this? – SnyersK Apr 22 '16 at 08:52
  • @SnyersK have a look at the created class files in your *build/intermediates/classes* folder. It should be an anonymous inner class. Then find out if proguard removed the class or the field. Also it would be interesting to know what exactly `Lif` is. – tynn Apr 22 '16 at 09:05
  • just updated my question with the code in the intermediates – SnyersK Apr 22 '16 at 09:15
1

I got the same problem. When i decompile the class i see question marks (??? should be arg0 in this case)

public static cr a(String arg0)
  {
    switch (???)
    {
    case "caseOne": 
      ??? = a;
      break;
    case "caseTwo": 
      ??? = f;
      break;
    default: 
      ??? = null;
    }
    return (cr)???;
  }

if you reassign the argument internally like

arg0= arg0.toLowerCase();

then proguard understands what to put instead of the question marks

public static cr a(String paramString)
  {
    switch (paramString = paramString.toLowerCase())
    {
    case "caseOne": 
      paramString = a;
      break;
    case "caseTwo": 
      paramString = f;
Stefan
  • 61
  • 1
  • 3