Repository: Kotlin/kotlinx.coroutines
File: kotlinx-coroutines-core/jvm/src/CoroutineExceptionHandlerImpl.kt (Kotlin)

Code before:
import kotlinx.coroutines.internal.*
import java.util.*
import kotlin.coroutines.*

/**
 * A list of globally installed [CoroutineExceptionHandler] instances.
 *
 * Note that Android may have dummy [Thread.contextClassLoader] which is used by one-argument [ServiceLoader.load] function,
 * see (https://stackoverflow.com/questions/13407006/android-class-loader-may-fail-for-processes-that-host-multiple-applications).
 * So here we explicitly use two-argument `load` with a class-loader of [CoroutineExceptionHandler] class.
 *
 * We are explicitly using the `ServiceLoader.load(MyClass::class.java, MyClass::class.java.classLoader).iterator()`
 * form of the ServiceLoader call to enable R8 optimization when compiled on Android.
 */
private val handlers: List<CoroutineExceptionHandler> by lazy {
    ServiceLoader.load(
        CoroutineExceptionHandler::class.java,
        CoroutineExceptionHandler::class.java.classLoader
    ).iterator().asSequence().toList()
}

internal actual fun initializeDefaultExceptionHandlers() {
    /**
     * For Android, we do not want to allow arbitrary disks read (service loader JAR scanning)
     * as it causes ANR, so we are postponing service loading until the actual exception (crash in case of Android).
     * For other applications it's not the issue to read the JAR, but it is the issue
     * to read from disk/call service loader when e.g. OOM was thrown, as exception reporting will also throw,
     * so we are initializing it eagerly.
     *
     * Alternatively, we can use our own FastServiceLoader (as for Dispatchers.Main) here as it gives x20 speedup, see
     * https://github.com/Kotlin/kotlinx.coroutines/issues/878#issuecomment-445815632
     * but it doesn't seem worth the trouble.
     */
    if (ANDROID_DETECTED) return
    // Load CEH and handlers
    CoroutineExceptionHandler
    handlers
}

/**
 * Private exception without stacktrace that is added to suppressed exceptions of the original exception
 * when it is reported to the last-ditch current thread 'uncaughtExceptionHandler'.
 *
 * The purpose of this exception is to add an otherwise inaccessible diagnostic information and to
 * be able to poke the failing coroutine context in the debugger.
 */
private class DiagnosticCoroutineContextException(private val context: CoroutineContext) : RuntimeException() {
    override fun getLocalizedMessage(): String {
        return context.toString()
    }


Review comment (bug):
```suggestion
     * For Android, we do not want to allow arbitrary disk reads (service loader JAR scanning)
     * as this would cause ANR, so we are postponing service loading until the actual exception (crash in case of Android).
     * For other applications, it's not an issue to read the JAR, but it is an issue
```

Code after:
import java.util.*
import kotlin.coroutines.*

/**
 * A list of globally installed [CoroutineExceptionHandler] instances.
 *
 * Note that Android may have dummy [Thread.contextClassLoader] which is used by one-argument [ServiceLoader.load] function,
 * see (https://stackoverflow.com/questions/13407006/android-class-loader-may-fail-for-processes-that-host-multiple-applications).
 * So here we explicitly use two-argument `load` with a class-loader of [CoroutineExceptionHandler] class.
 *
 * We are explicitly using the `ServiceLoader.load(MyClass::class.java, MyClass::class.java.classLoader).iterator()`
 * form of the ServiceLoader call to enable R8 optimization when compiled on Android.
 */
private val handlers: List<CoroutineExceptionHandler> = ServiceLoader.load(
        CoroutineExceptionHandler::class.java,
        CoroutineExceptionHandler::class.java.classLoader
).iterator().asSequence().toList()

/**
 * Private exception without stacktrace that is added to suppressed exceptions of the original exception
 * when it is reported to the last-ditch current thread 'uncaughtExceptionHandler'.
 *
 * The purpose of this exception is to add an otherwise inaccessible diagnostic information and to
 * be able to poke the failing coroutine context in the debugger.
 */
private class DiagnosticCoroutineContextException(private val context: CoroutineContext) : RuntimeException() {
    override fun getLocalizedMessage(): String {
        return context.toString()
    }

    override fun fillInStackTrace(): Throwable {
        // Prevent Android <= 6.0 bug, #1866
        stackTrace = emptyArray()
        return this
    }
}

internal actual fun handleCoroutineExceptionImpl(context: CoroutineContext, exception: Throwable) {
    // use additional extension handlers
    for (handler in handlers) {
        try {
            handler.handleException(context, exception)
        } catch (t: Throwable) {
            // Use thread's handler if custom handler failed to handle exception
            val currentThread = Thread.currentThread()
            currentThread.uncaughtExceptionHandler.uncaughtException(currentThread, handlerException(exception, t))
        }
    }

    // use thread's handler
    val currentThread = Thread.currentThread()