Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dexguard / Proguard make app crash on Enum switch

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.

like image 944
SnyersK Avatar asked Oct 31 '22 05:10

SnyersK


2 Answers

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.

like image 185
tynn Avatar answered Nov 09 '22 07:11

tynn


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;
like image 43
Stefan Avatar answered Nov 09 '22 06:11

Stefan