Description
Here is simple example:
runBlocking {
val job = launch {
try {
delay(1000)
} catch (e: Exception) {
e.stackTrace // accessing 'stackTrace' lead to crash
}
}
yield()
job.cancelAndJoin()
}
When you run the code above on Android 6.0 and lower, application will crash with following exception:
java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.Object java.lang.Object.clone()' on a null object reference
The analogue issue is akaita/RxJava2Debug#2
Due to the bug on Android 6.0 and below, when you override fillInStackTrace
and don't call super method, under-the-hood the exception stack trace not filled by nativeFillInStackTrace() method, so next time when you try to call getStackTrace(), under-the-hood the nativeGetStackTrace() method will return null
and clone() will be called on that null
.
Solution
To fix this issue you should set empty stack trace, when overriding fillInStackTrace
method, like following:
override fun fillInStackTrace(): Throwable {
stackTrace = emptyArray<StackTraceElement>()
return this
}
Also to reduce garbage, this empty array can be defined as global constant.
This fix must be applied to all custom exceptions, those override fillInStackTrace
, currently these are:
Workaround
Enable Debug Mode, so that fillInStackTrace
will work as expected.