Menu

#716 Verification error due to bad private default constructor

v5.3.3
closed-rejected
None
High
2018-07-23
2018-07-21
Andreas
No

I use Proguard 6.0.1 by enforcement within Android Studio 2.3 due to another error (similar to https://sourceforge.net/p/proguard/bugs/682/ ). I enforce this version in my top-level build.gradle:

buildscript {
    configurations.all {
        resolutionStrategy {
            force 'net.sf.proguard:proguard-gradle:6.0.1'
        }
    }
    ...
    dependencies {
        classpath 'com.android.tools.build:gradle:2.3.0'
        classpath 'me.tatarka:gradle-retrolambda:3.6.1'
}
...

The most important proguard options I use:

# retrolambda:
-dontwarn java.lang.invoke.*
-dontwarn **$$Lambda$*
# /retrolambda

-flattenpackagehierarchy
-dontshrink # todo temporary - Takes very long
#-optimizations "code/removal/*,code/simplification/*" # No error with this, but ignores -assumenosideeffects

-keep class android.*
-keep class java.*
-keep class sun.*

-keepnames class android.support.multidex.* {
    *;
}

# Update of proguard-android file:
-keepclassmembers,allowoptimization enum * {
    public static **[] values();
    public static ** valueOf(java.lang.String);
}

-assumenosideeffects class my.project.* {
    static void f();
    void f();
}

-assumenosideeffects class my.project.util.Utils {
    public static Object noSideEffects(...);
}

-assumenosideeffects public interface my.project.util.function.NoSideEffectsSupplier { *; }

-assumenosideeffects class my.project.util.logging.SLogger {
    public void f(...);
    public void fs(...);
}

-assumenosideeffects class android.util.Log {
    public static int v(...);
    public static int d(...);
}
-assumenosideeffects class java.io.PrintStream {
     public void println(%);
     public void println(**);
 }

From the apps build.gradle:

android {
    ...
    // retrolambda
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
    // / retrolambda
    buildTypes {
        release {
            minifyEnabled true
            shrinkResources true
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
            lintOptions {
                disable 'MissingTranslation'
            }
        }
    }
}

dependencies {
    compile 'com.android.support:multidex:1.0.1'
    ...
}

apply plugin: 'me.tatarka.retrolambda'

I manually install the signed release build on a device, but on app launch I get this error:

I/art: Verification error in void android.support.multidex.MultiDex.<init>()
I/art: void android.support.multidex.MultiDex.<init>() failed to verify: void android.support.multidex.MultiDex.<init>(): [0x0] Constructor returning without calling superclass constructor
E/art: Verification failed on class android.support.multidex.MultiDex in /data/app/my.project.android.myapp-1/base.apk because: Verifier rejected class android.support.multidex.MultiDex due to bad method void android.support.multidex.MultiDex.<init>()
D/AndroidRuntime: Shutting down VM


                  --------- beginning of crash
E/AndroidRuntime: FATAL EXCEPTION: main
                  Process: my.project.android.myapp, PID: 11014
                  java.lang.VerifyError: Verifier rejected class android.support.multidex.MultiDex due to bad method void android.support.multidex.MultiDex.<init>() (declaration of 'android.support.multidex.MultiDex' appears in /data/app/my.project.android.myapp-1/base.apk)
                      at my.project.android.myapp.MyApp.attachBaseContext(Unknown Source)
                      at android.app.Application.attach(Application.java:181)
                      at android.app.Instrumentation.newApplication(Instrumentation.java:996)
                      at android.app.Instrumentation.newApplication(Instrumentation.java:980)
                      at android.app.LoadedApk.makeApplication(LoadedApk.java:564)
                      at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4634)
                      at android.app.ActivityThread.access$1500(ActivityThread.java:156)
                      at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1412)
                      at android.os.Handler.dispatchMessage(Handler.java:102)
                      at android.os.Looper.loop(Looper.java:211)
                      at android.app.ActivityThread.main(ActivityThread.java:5389)
                      at java.lang.reflect.Method.invoke(Native Method)
                      ...

I get the same error when omitting the following rule:

-keepnames class android.support.multidex.* {
    *;
}

I get no error when uncommenting this line:

-optimizations "code/removal/*,code/simplification/*"

But then, -assumenosideeffects will be ignored. I dont want to miss any optimizations.

The problem is the loading of the MultiDex class which is a library by Android (which does not use Retrolambda), but somehow ProGuard seems to corrcupt it. Probably v6 is responsible for this.

Discussion

  • Andreas

    Andreas - 2018-07-21

    With limited optimizations, the bytecode viewer shows the MultiDex private constructor as

    private MultiDex() { // <init> //()V
             aload0 // reference to self
             invokespecial java/lang/Object.<init>()V
             return
     }
    

    and with full optimizations:

    private MultiDex() { // <init> //()V
             return
     }
    
     
  • Eric Lafortune

    Eric Lafortune - 2018-07-22

    The problem is caused by

    -assumenosideeffects public interface my.project.util.function.NoSideEffectsSupplier { *; }
    

    The wildcard also matches the constructor, which spills over to the constructor of Object. ProGuard then removes all calls to Object.<init>, which breaks other code. ProGuard probably already prints out a warning about the setting; you should generally avoid wildcards in -assumenosideeffects. You should also be very careful about removing println calls, since some code may really require them.</init>

     
  • Eric Lafortune

    Eric Lafortune - 2018-07-22
    • status: open --> closed-rejected
    • assigned_to: Eric Lafortune
     
  • Andreas

    Andreas - 2018-07-23

    Thanks for this information! Now it works.

    I still need to solve the following problem: I'd like to have a certain API to run commands as explicitly without side-effects, like this:

    Utils.noSideEffects(this::command);
    Utils.noSideEffects(() -> { ... });
    Utils.noSideEffects(new NoSideEffectsRunnable() {
                @Override
                public void run() {
                    ...
                }
            }); // Java 7
    

    My rules to remove such calls currently are:

    -assumenosideeffects class my.project.util.Utils {
        public static Object noSideEffects(...);
        public static void noSideEffects(...);
    }
    -assumenosideeffects class * implements my.project.util.function.NoSideEffectsRunnable {
        public <init>();
        public void run();
    }
    

    But the call will not be removed, probably because the init rule for subclasses is not sufficient. How can I accomplish the complete removement of Utils.noSideEffects() without getting errors?

     

    Last edit: Andreas 2018-07-23

Log in to post a comment.

MongoDB Logo MongoDB