Status Update
Comments
ch...@google.com <ch...@google.com>
th...@gmail.com <th...@gmail.com> #2
R8 version 1.6.82 in combination with Android Gradle Plugin 3.6.2 which I was using before, does not have this issue.
ch...@google.com <ch...@google.com> #3
Thanks for all the details! Since this only happens in full mode this could be due to inadequate keep rules. I will try to inspect the byte code in an attempt to find the root cause of the problem.
Would it be possible for you to share two apks built with R8 2.0.59, where one is built with Proguard compatibility mode (default) and the other is built with full mode? It would also be helpful if you could share the mapping file and your Proguard configuration with
th...@gmail.com <th...@gmail.com> #4
I just sent you an email with the files.
Also I forgot to mention that I am using Kotlin 1.3.72, Coroutines 1.3.5-native-mt, and Ktor 1.3.2, in case that is related to this issue.
th...@gmail.com <th...@gmail.com> #5
Building an APK with the option -dontobfuscate shows the following stack trace. You can find this apk in your email as well.
2020-04-22 11:15:06.453 15812-16044/? E/AndroidRuntime: FATAL EXCEPTION: OkHttp Dispatcher
Process: com.superthomaslab.hueessentials, PID: 15812
java.lang.ClassCastException: -$$LambdaGroup$ks$Ko6AyJbCP1F5q3JO0ni8Us7kSws cannot be cast to io.ktor.util.StringValuesBuilder$appendAll$1
at io.ktor.util.StringValuesSingleImpl.forEach(SourceFile:1)
at com.superthomaslab.hueessentials.common.data.networking.KtorKt$addHeadersAfterRequest$1$$special$$inlined$-addNetworkInterceptor$1.intercept(SourceFile:4)
at okhttp3.internal.http.RealInterceptorChain.proceed(SourceFile:12)
at okhttp3.internal.connection.ConnectInterceptor.intercept(SourceFile:23)
at okhttp3.internal.http.RealInterceptorChain.proceed(SourceFile:12)
at okhttp3.internal.cache.CacheInterceptor.intercept(SourceFile:183)
at okhttp3.internal.http.RealInterceptorChain.proceed(SourceFile:12)
at okhttp3.internal.http.BridgeInterceptor.intercept(SourceFile:24)
at okhttp3.internal.http.RealInterceptorChain.proceed(SourceFile:12)
at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(SourceFile:36)
at okhttp3.internal.http.RealInterceptorChain.proceed(SourceFile:12)
at okhttp3.internal.http.RealInterceptorChain.proceed(SourceFile:1)
at okhttp3.RealCall.getResponseWithInterceptorChain(SourceFile:24)
at okhttp3.RealCall$AsyncCall.run(SourceFile:12)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:919)
ch...@google.com <ch...@google.com> #6
Thanks for sharing the apks! After looking into the bytecode, I am wondering if this is an issue in the propagation of arguments from call sites to method entries since it seems that the devirtualizer has made an unsound decision based on the type of an argument.
Does the app work with full mode if you add the following rule?
-keep,allowobfuscation class io.ktor.util.StringValuesSingleImpl { void forEach(kotlin.jvm.functions.Function2); }
If you build with the following command (without the above keep rule), you should see some extensive logging for the method in which the error has been introduced that could be helpful in diagnosing this issue:
./gradlew assembleRelease -Dcom.android.tools.r8.extensiveLoggingFilter="void io.ktor.util.StringValuesSingleImpl.forEach(kotlin.jvm.functions.Function2)" --no-daemon
Finally, would it be possible for you to share a dump of the build containing the JVM class files? You can create a dump by running the following command:
./gradlew assembleRelease -Dcom.android.tools.r8.dumpinputtofile=/path/to/write/dump.zip --no-daemon
th...@gmail.com <th...@gmail.com> #7
Does the app work with full mode if you add the following rule?
Yes, this fixes the issue. I sent you the APK by email.
If you build with the following command (without the above keep rule), you should see some extensive logging for the method in which the error has been introduced that could be helpful in diagnosing this issue
Here is the output with the extensive logging:
thomas@Thomass-Mac-mini HueEssentials % ./gradlew :android:app:assembleGooglePlayRelease -Dcom.android.tools.r8.extensiveLoggingFilter="void io.ktor.util.StringValuesSingleImpl.forEach(kotlin.jvm.functions.Function2)" --no-daemon
(…)
> Task :android:app:minifyGooglePlayReleaseWithR8
R8: Missing class: org.conscrypt.ConscryptHostnameVerifier
Entering phase: Primary optimization pass
-----------------------------------------------------------------------
Initial IR (SSA)
-----------------------------------------------------------------------
blocks:
block 0, pred-counts: 0, succ-count: 0, filled: true, sealed: true
predecessors: -
successors: -
no phis
#0: -1: g v0 <-
: -1: g v1 <-
: -1: B v2 <- "body"
: -1: Invoke-Static v1, v2; method: void kotlin.jvm.internal.Intrinsics.checkParameterIsNotNull(java.lang.Object, java.lang.String)
#106: -1: e0 v3 <- v0; field: java.lang.String io.ktor.util.StringValuesSingleImpl.name
: -1: e0 v4 <- v0; field: java.util.List io.ktor.util.StringValuesSingleImpl.values
: -1: Invoke-Interface v5 <- v1, v3, v4; method: java.lang.Object kotlin.jvm.functions.Function2.invoke(java.lang.Object, java.lang.Object)
: -1: U0
-----------------------------------------------------------------------
-----------------------------------------------------------------------
IR after disable assertions (SSA)
-----------------------------------------------------------------------
blocks:
block 0, pred-counts: 0, succ-count: 0, filled: true, sealed: true
predecessors: -
successors: -
no phis
#0: -1: g v0 <-
: -1: g v1 <-
: -1: B v2 <- "body"
#106: -1: e0 v3 <- v0; field: java.lang.String io.ktor.util.StringValuesSingleImpl.name
: -1: e0 v4 <- v0; field: java.util.List io.ktor.util.StringValuesSingleImpl.values
: -1: Invoke-Interface v5 <- v1, v3, v4; method: java.lang.Object kotlin.jvm.functions.Function2.invoke(java.lang.Object, java.lang.Object)
: -1: U0
-----------------------------------------------------------------------
-----------------------------------------------------------------------
IR after inserting assume instructions (SSA)
-----------------------------------------------------------------------
blocks:
block 0, pred-counts: 0, succ-count: 0, filled: true, sealed: true
predecessors: -
successors: -
no phis
#0: -1: g v0 <-
: -1: g v1 <-
: -1: B v2 <- "body"
#106: -1: e0 v3 <- v0; field: java.lang.String io.ktor.util.StringValuesSingleImpl.name
: -1: e0 v4 <- v0; field: java.util.List io.ktor.util.StringValuesSingleImpl.values
: -1: Invoke-Interface v5 <- v1, v3, v4; method: java.lang.Object kotlin.jvm.functions.Function2.invoke(java.lang.Object, java.lang.Object)
: -1: AssumeNonNull v6 <- v1 (origin: `Invoke-Interface v5 <- v1, v3, v4; method: java.lang.Object kotlin.jvm.functions.Function2.invoke(java.lang.Object, java.lang.Object)`)
: -1: U0
-----------------------------------------------------------------------
-----------------------------------------------------------------------
IR after generated extension registry shrinking (SSA)
-----------------------------------------------------------------------
Unchanged
-----------------------------------------------------------------------
-----------------------------------------------------------------------
IR after generated message lite shrinking (SSA)
-----------------------------------------------------------------------
Unchanged
-----------------------------------------------------------------------
-----------------------------------------------------------------------
IR after inlining (SSA)
-----------------------------------------------------------------------
Unchanged
-----------------------------------------------------------------------
-----------------------------------------------------------------------
IR after lambda desugaring (SSA)
-----------------------------------------------------------------------
blocks:
block 0, pred-counts: 0, succ-count: 0, filled: true, sealed: true
predecessors: -
successors: -
no phis
#0: -1: g v0 <-
: -1: g v1 <-
#106: -1: e0 v3 <- v0; field: java.lang.String io.ktor.util.StringValuesSingleImpl.name
: -1: e0 v4 <- v0; field: java.util.List io.ktor.util.StringValuesSingleImpl.values
: -1: Invoke-Interface v1, v3, v4; method: java.lang.Object kotlin.jvm.functions.Function2.invoke(java.lang.Object, java.lang.Object)
: -1: U0
-----------------------------------------------------------------------
-----------------------------------------------------------------------
IR before class inlining (SSA)
-----------------------------------------------------------------------
Unchanged
-----------------------------------------------------------------------
-----------------------------------------------------------------------
IR after class inlining (SSA)
-----------------------------------------------------------------------
Unchanged
-----------------------------------------------------------------------
-----------------------------------------------------------------------
IR after nest based access desugaring (SSA)
-----------------------------------------------------------------------
Unchanged
-----------------------------------------------------------------------
-----------------------------------------------------------------------
IR after interface method rewriting (SSA)
-----------------------------------------------------------------------
Unchanged
-----------------------------------------------------------------------
-----------------------------------------------------------------------
IR after desugared library API Conversion (SSA)
-----------------------------------------------------------------------
Unchanged
-----------------------------------------------------------------------
-----------------------------------------------------------------------
IR after twr close resource rewriter (SSA)
-----------------------------------------------------------------------
Unchanged
-----------------------------------------------------------------------
-----------------------------------------------------------------------
IR after lambda merger (SSA)
-----------------------------------------------------------------------
Unchanged
-----------------------------------------------------------------------
-----------------------------------------------------------------------
IR after outline handler (SSA)
-----------------------------------------------------------------------
Unchanged
-----------------------------------------------------------------------
-----------------------------------------------------------------------
IR after idempotent function call canonicalization (SSA)
-----------------------------------------------------------------------
Unchanged
-----------------------------------------------------------------------
-----------------------------------------------------------------------
IR after argument type logging (SSA)
-----------------------------------------------------------------------
Unchanged
-----------------------------------------------------------------------
-----------------------------------------------------------------------
IR after computation of optimization info summary (SSA)
-----------------------------------------------------------------------
Unchanged
-----------------------------------------------------------------------
-----------------------------------------------------------------------
Optimized IR (SSA)
-----------------------------------------------------------------------
Unchanged
-----------------------------------------------------------------------
-----------------------------------------------------------------------
After register allocation (non-SSA)
-----------------------------------------------------------------------
blocks:
block 0, pred-counts: 0, succ-count: 0, filled: true, sealed: true
predecessors: -
successors: -
no phis
#0: 0: g v0 <-
: 2: g v1 <-
#106: 4: e0 v3 <- v0; field: java.lang.String io.ktor.util.StringValuesSingleImpl.name
: 6: e0 v4 <- v0; field: java.util.List io.ktor.util.StringValuesSingleImpl.values
: 8: Invoke-Interface v1, v3, v4; method: java.lang.Object kotlin.jvm.functions.Function2.invoke(java.lang.Object, java.lang.Object)
: 10: U0
-----------------------------------------------------------------------
-----------------------------------------------------------------------
Final IR (non-SSA)
-----------------------------------------------------------------------
blocks:
block 0, pred-counts: 0, succ-count: 0, filled: true, sealed: true
predecessors: -
successors: -
no phis
#0: 0: g v0 <-
: 2: g v1 <-
#106: 4: e0 v3 <- v0; field: java.lang.String io.ktor.util.StringValuesSingleImpl.name
: 6: e0 v4 <- v0; field: java.util.List io.ktor.util.StringValuesSingleImpl.values
: 8: Invoke-Interface v1, v3, v4; method: java.lang.Object kotlin.jvm.functions.Function2.invoke(java.lang.Object, java.lang.Object)
: 10: U0
-----------------------------------------------------------------------
> Task :android:app:minifyGooglePlayReleaseWithR8
Entering phase: Post optimization pass
-----------------------------------------------------------------------
Initial IR (SSA)
-----------------------------------------------------------------------
blocks:
block 0, pred-counts: 0, succ-count: 0, filled: true, sealed: true
predecessors: -
successors: -
no phis
#0: -1: g v0 <-
: -1: g v1 <-
: -1: AssumeDynamicType v4 <- v1; upper bound: @NotNull io.ktor.util.StringValuesBuilder$appendAll$1 {kotlin.jvm.internal.FunctionBase, java.io.Serializable, kotlin.jvm.functions.Function2} (origin: `g v1 <- `)
: -1: AssumeNonNull v5 <- v4 (origin: `g v1 <- `)
#106: -1: e0 v2 <- v0; field: java.lang.String io.ktor.util.StringValuesSingleImpl.name
: -1: e0 v3 <- v0; field: java.util.List io.ktor.util.StringValuesSingleImpl.values
: -1: Invoke-Interface v5, v2, v3; method: java.lang.Object kotlin.jvm.functions.Function2.invoke(java.lang.Object, java.lang.Object)
: -1: U0
-----------------------------------------------------------------------
-----------------------------------------------------------------------
IR after disable assertions (SSA)
-----------------------------------------------------------------------
Unchanged
-----------------------------------------------------------------------
-----------------------------------------------------------------------
IR after inserting assume instructions (SSA)
-----------------------------------------------------------------------
Unchanged
-----------------------------------------------------------------------
-----------------------------------------------------------------------
IR after generated extension registry shrinking (SSA)
-----------------------------------------------------------------------
Unchanged
-----------------------------------------------------------------------
-----------------------------------------------------------------------
IR after generated message lite shrinking (SSA)
-----------------------------------------------------------------------
Unchanged
-----------------------------------------------------------------------
-----------------------------------------------------------------------
IR after inlining (SSA)
-----------------------------------------------------------------------
Unchanged
-----------------------------------------------------------------------
-----------------------------------------------------------------------
IR after lambda desugaring (SSA)
-----------------------------------------------------------------------
blocks:
block 0, pred-counts: 0, succ-count: 0, filled: true, sealed: true
predecessors: -
successors: -
no phis
#0: -1: g v0 <-
: -1: g v1 <-
: -1: AssumeDynamicType v4 <- v1; upper bound: @NotNull io.ktor.util.StringValuesBuilder$appendAll$1 {kotlin.jvm.internal.FunctionBase, java.io.Serializable, kotlin.jvm.functions.Function2} (origin: `g v1 <- `)
: -1: AssumeNonNull v5 <- v4 (origin: `g v1 <- `)
#106: -1: e0 v2 <- v0; field: java.lang.String io.ktor.util.StringValuesSingleImpl.name
: -1: e0 v3 <- v0; field: java.util.List io.ktor.util.StringValuesSingleImpl.values
: -1: u v6 <- v5; io.ktor.util.StringValuesBuilder$appendAll$1
: -1: Invoke-Virtual v6, v2, v3; method: java.lang.Object io.ktor.util.StringValuesBuilder$appendAll$1.invoke(java.lang.Object, java.lang.Object)
: -1: U0
-----------------------------------------------------------------------
-----------------------------------------------------------------------
IR before class inlining (SSA)
-----------------------------------------------------------------------
Unchanged
-----------------------------------------------------------------------
-----------------------------------------------------------------------
IR after class inlining (SSA)
-----------------------------------------------------------------------
Unchanged
-----------------------------------------------------------------------
-----------------------------------------------------------------------
IR after nest based access desugaring (SSA)
-----------------------------------------------------------------------
Unchanged
-----------------------------------------------------------------------
-----------------------------------------------------------------------
IR after interface method rewriting (SSA)
-----------------------------------------------------------------------
Unchanged
-----------------------------------------------------------------------
-----------------------------------------------------------------------
IR after desugared library API Conversion (SSA)
-----------------------------------------------------------------------
Unchanged
-----------------------------------------------------------------------
-----------------------------------------------------------------------
IR after twr close resource rewriter (SSA)
-----------------------------------------------------------------------
Unchanged
-----------------------------------------------------------------------
-----------------------------------------------------------------------
IR after lambda merger (SSA)
-----------------------------------------------------------------------
Unchanged
-----------------------------------------------------------------------
-----------------------------------------------------------------------
IR after outline handler (SSA)
-----------------------------------------------------------------------
Unchanged
-----------------------------------------------------------------------
-----------------------------------------------------------------------
IR after idempotent function call canonicalization (SSA)
-----------------------------------------------------------------------
Unchanged
-----------------------------------------------------------------------
-----------------------------------------------------------------------
IR after argument type logging (SSA)
-----------------------------------------------------------------------
Unchanged
-----------------------------------------------------------------------
-----------------------------------------------------------------------
IR after computation of optimization info summary (SSA)
-----------------------------------------------------------------------
blocks:
block 0, pred-counts: 0, succ-count: 0, filled: true, sealed: true
predecessors: -
successors: -
no phis
#0: -1: g v0 <-
: -1: g v1 <-
#106: -1: e0 v2 <- v0; field: java.lang.String io.ktor.util.StringValuesSingleImpl.name
: -1: e0 v3 <- v0; field: java.util.List io.ktor.util.StringValuesSingleImpl.values
: -1: u v6 <- v1; io.ktor.util.StringValuesBuilder$appendAll$1
: -1: Invoke-Virtual v6, v2, v3; method: java.lang.Object io.ktor.util.StringValuesBuilder$appendAll$1.invoke(java.lang.Object, java.lang.Object)
: -1: U0
-----------------------------------------------------------------------
-----------------------------------------------------------------------
Optimized IR (SSA)
-----------------------------------------------------------------------
Unchanged
-----------------------------------------------------------------------
-----------------------------------------------------------------------
After register allocation (non-SSA)
-----------------------------------------------------------------------
blocks:
block 0, pred-counts: 0, succ-count: 0, filled: true, sealed: true
predecessors: -
successors: -
no phis
#0: 0: g v0 <-
: 2: g v1 <-
#106: 4: e0 v2 <- v0; field: java.lang.String io.ktor.util.StringValuesSingleImpl.name
: 6: e0 v3 <- v0; field: java.util.List io.ktor.util.StringValuesSingleImpl.values
: 8: u v6 <- v1; io.ktor.util.StringValuesBuilder$appendAll$1
: 10: Invoke-Virtual v6, v2, v3; method: java.lang.Object io.ktor.util.StringValuesBuilder$appendAll$1.invoke(java.lang.Object, java.lang.Object)
: 12: U0
-----------------------------------------------------------------------
-----------------------------------------------------------------------
Final IR (non-SSA)
-----------------------------------------------------------------------
blocks:
block 0, pred-counts: 0, succ-count: 0, filled: true, sealed: true
predecessors: -
successors: -
no phis
#0: 0: g v0 <-
: 2: g v1 <-
#106: 4: e0 v2 <- v0; field: java.lang.String io.ktor.util.StringValuesSingleImpl.name
: 6: e0 v3 <- v0; field: java.util.List io.ktor.util.StringValuesSingleImpl.values
: 8: u v6 <- v1; io.ktor.util.StringValuesBuilder$appendAll$1
: 10: Invoke-Virtual v6, v2, v3; method: java.lang.Object io.ktor.util.StringValuesBuilder$appendAll$1.invoke(java.lang.Object, java.lang.Object)
: 12: U0
-----------------------------------------------------------------------
> Task :android:app:minifyGooglePlayReleaseWithR8
Entering phase: Class staticizer post processing
Entering phase: Lambda class synthesis
Entering phase: Interface method desugaring
Entering phase: Twr close resource utility class synthesis
Entering phase: Lambda merging finalization
Entering phase: Desugared library API Conversion finalization
Entering phase: Outlining
Deprecated Gradle features were used in this build, making it incompatible with Gradle 7.0.
Use '--warning-mode all' to show the individual deprecation warnings.
See https://docs.gradle.org/6.1.1/userguide/command_line_interface.html#sec:command_line_warnings
BUILD SUCCESSFUL in 3m 54s
89 actionable tasks: 76 executed, 12 from cache, 1 up-to-date
thomas@Thomass-Mac-mini HueEssentials %
Finally, would it be possible for you to share a dump of the build containing the JVM class files? You can create a dump by running the following command
I'm not sure whether you mean with or without the keep rule above, so I built it twice. For some reason there is a massive file size difference in the output. It also looks like the dump without the keep rule got an error. You can find the dumps and terminal output in your email, too. Please check the terminal output as I think something went wrong. (I tried building again but that didn't make any difference)
ap...@google.com <ap...@google.com> #8
Branch: master
commit 96ea16b3324e42a44bcb56c69b6d6b7aee4a8e4c
Author: Christoffer Quist Adamsen <christofferqa@google.com>
Date: Mon Apr 27 14:33:06 2020
Reproduce missing propagation in call site optimization
Bug: 154531810
Change-Id: Id4af6e1d2165ea48d010a7b14c3fee6739aa59a8
A src/test/java/com/android/tools/r8/ir/optimize/callsites/PropagationFromSiblingTest.java
ap...@google.com <ap...@google.com> #9
Branch: 2.0
commit 980a7a5e2d93f98dcae3f947b3911162497fcf59
Author: Christoffer Quist Adamsen <christofferqa@google.com>
Date: Tue Apr 28 11:10:33 2020
Version 2.0.71
Cherry pick: Reproduce missing propagation in call site optimization
CL:
In addition to cherry picking the test case from the CL above, this version includes a fix to InvokeMethod.lookupTargets(), which would incorrectly filter out possible dispatch targets, causing a bug in the call site optimization.
Bug: 154531810
Change-Id: Id4af6e1d2165ea48d010a7b14c3fee6739aa59a8
M src/main/java/com/android/tools/r8/Version.java
M src/main/java/com/android/tools/r8/ir/code/InvokeMethod.java
A src/test/java/com/android/tools/r8/ir/optimize/callsites/PropagationFromSiblingTest.java
ch...@google.com <ch...@google.com> #10
Thanks again for the help in diagnosing this issue.
The issue is fixed in R8 2.0.71, which should make it into the AGP 4.0 stable release.
You can build with this version of R8 until AGP 4.0 is available b y amking the following changes to build.gradle:
buildscript {
repositories {
maven {
url 'https://storage.googleapis.com/r8-releases/raw'
}
}
dependencies {
classpath 'com.android.tools:r8:2.0.71' // Must be before the Gradle Plugin for Android.
classpath 'com.android.tools.build:gradle:X.Y.Z' // Your current AGP version.
}
}
I will mark this as fixed, but please don't hesitate to reopen if you are still seeing the ClassCastException with 2.0.71.
th...@gmail.com <th...@gmail.com> #11
Thanks a lot! I can confirm the issue is now fixed in my app as well.
b9...@gmail.com <b9...@gmail.com> #12
BTW how do I check which R8 version does AGP 4.0 used?
ch...@google.com <ch...@google.com> #13
If you build with ./gradlew assembleRelease --info
the version of R8 should be printed.
ey...@gmail.com <ey...@gmail.com> #14
Not sure if this issue is related to
ri...@google.com <ri...@google.com> #15
Morten: The linked issue is in kotlin coroutines, can you take a look? (maybe we should start a new bug on our side for this)
ze...@google.com <ze...@google.com> #16
Unfortunately that is a device specific issue and we have not yet been able to pin-point the exact bug in the VM.
Description
After updating the Android Gradle plugin from version 3.6.2 to 4.0.0-beta04 I get a ClassCastException in a release build:
The above stack trace retraced manually:
And another reported stack trace through Firebase (retraced automatically) which looks a bit different:
This is part of the code in the stack trace (Ktor.kt):
Some more details:
See the attached APK which crashes. I can share the mapping / app bundle privately if needed.
Steps to reproduce in the attached APK:
I am trying to reproduce this in a sample project, but no luck so far.