Skip to content

Accessing 'stackTrace' on JobCancellationException instance leads to crash on Android 6.0 and below #1866

Closed
@varahash

Description

@varahash

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:

internal actual class JobCancellationException public actual constructor(

internal actual class AbortFlowException actual constructor(

internal actual class ChildCancelledException : CancellationException("Child of the scoped flow was cancelled") {

Workaround
Enable Debug Mode, so that fillInStackTrace will work as expected.

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions