Skip to content

Commit b79daf2

Browse files
committed
Use 'Class.forName($name).canonicalName' instead of '$name' in stacktrace recovery to properly deal with Android's minifier
Fixes #1416
1 parent 3f16360 commit b79daf2

File tree

1 file changed

+18
-4
lines changed

1 file changed

+18
-4
lines changed

kotlinx-coroutines-core/jvm/src/internal/StackTraceRecovery.kt

+18-4
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,21 @@ import java.util.*
1111
import kotlin.coroutines.*
1212
import kotlin.coroutines.intrinsics.*
1313

14+
/*
15+
* `Class.forName(name).canonicalName` instead of plain `name` is required to properly handle
16+
* Android's minifier that renames these classes and breaks our recovery heuristic without such lookup.
17+
*/
18+
private const val baseContinuationImplClass = "kotlin.coroutines.jvm.internal.BaseContinuationImpl"
19+
private const val stackTraceRecoveryClass = "kotlinx.coroutines.internal.StackTraceRecoveryKt"
20+
21+
private val baseContinuationImplClassName = runCatching {
22+
Class.forName(baseContinuationImplClass).canonicalName
23+
}.getOrElse { baseContinuationImplClass }
24+
25+
private val stackTraceRecoveryClassName = runCatching {
26+
Class.forName(stackTraceRecoveryClass).canonicalName
27+
}.getOrElse { stackTraceRecoveryClass }
28+
1429
internal actual fun <E : Throwable> recoverStackTrace(exception: E): E {
1530
if (recoveryDisabled(exception)) return exception
1631
// No unwrapping on continuation-less path: exception is not reported multiple times via slow paths
@@ -21,10 +36,9 @@ internal actual fun <E : Throwable> recoverStackTrace(exception: E): E {
2136
private fun <E : Throwable> E.sanitizeStackTrace(): E {
2237
val stackTrace = stackTrace
2338
val size = stackTrace.size
24-
25-
val lastIntrinsic = stackTrace.frameIndex("kotlinx.coroutines.internal.StackTraceRecoveryKt")
39+
val lastIntrinsic = stackTrace.frameIndex(stackTraceRecoveryClassName)
2640
val startIndex = lastIntrinsic + 1
27-
val endIndex = stackTrace.frameIndex("kotlin.coroutines.jvm.internal.BaseContinuationImpl")
41+
val endIndex = stackTrace.frameIndex(baseContinuationImplClassName)
2842
val adjustment = if (endIndex == -1) 0 else size - endIndex
2943
val trace = Array(size - lastIntrinsic - adjustment) {
3044
if (it == 0) {
@@ -83,7 +97,7 @@ private fun <E : Throwable> recoverFromStackFrame(exception: E, continuation: Co
8397
private fun <E : Throwable> createFinalException(cause: E, result: E, resultStackTrace: ArrayDeque<StackTraceElement>): E {
8498
resultStackTrace.addFirst(artificialFrame("Coroutine boundary"))
8599
val causeTrace = cause.stackTrace
86-
val size = causeTrace.frameIndex("kotlin.coroutines.jvm.internal.BaseContinuationImpl")
100+
val size = causeTrace.frameIndex(baseContinuationImplClassName)
87101
if (size == -1) {
88102
result.stackTrace = resultStackTrace.toTypedArray()
89103
return result

0 commit comments

Comments
 (0)