Skip to content

Circular Exception delivered to invokeOnCompletion #305

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
FabianFrank opened this issue Mar 28, 2018 · 4 comments
Closed

Circular Exception delivered to invokeOnCompletion #305

FabianFrank opened this issue Mar 28, 2018 · 4 comments
Labels

Comments

@FabianFrank
Copy link

It seems that Kotlin can create Throwables with circular references. While methods like printStackTrace() tend to handle this well, a lot of logging frameworks crash or go into an infinite loop when encountering these.

Kotlin program:

import kotlinx.coroutines.experimental.launch
import kotlinx.coroutines.experimental.runBlocking


fun main(args: Array<String>) {
    val job = launch {
        println("A")

        launch(coroutineContext) {
            println("B")
            throw RuntimeException("foobar")
        }
    }
    job.invokeOnCompletion {
        it!!.printStackTrace()
    }

    runBlocking {
        job.join()
    }
}

Output:

/Library/Java/JavaVirtualMachines/jdk1.8.0_162.jdk/Contents/Home/bin/java "-javaagent:/Applications/IntelliJ IDEA CE.app/Contents/lib/idea_rt.jar=51858:/Applications/IntelliJ IDEA CE.app/Contents/bin" -Dfile.encoding=UTF-8 -classpath /Library/Java/JavaVirtualMachines/jdk1.8.0_162.jdk/Contents/Home/jre/lib/charsets.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_162.jdk/Contents/Home/jre/lib/deploy.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_162.jdk/Contents/Home/jre/lib/ext/cldrdata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_162.jdk/Contents/Home/jre/lib/ext/dnsns.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_162.jdk/Contents/Home/jre/lib/ext/jaccess.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_162.jdk/Contents/Home/jre/lib/ext/jfxrt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_162.jdk/Contents/Home/jre/lib/ext/localedata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_162.jdk/Contents/Home/jre/lib/ext/nashorn.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_162.jdk/Contents/Home/jre/lib/ext/sunec.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_162.jdk/Contents/Home/jre/lib/ext/sunjce_provider.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_162.jdk/Contents/Home/jre/lib/ext/sunpkcs11.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_162.jdk/Contents/Home/jre/lib/ext/zipfs.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_162.jdk/Contents/Home/jre/lib/javaws.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_162.jdk/Contents/Home/jre/lib/jce.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_162.jdk/Contents/Home/jre/lib/jfr.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_162.jdk/Contents/Home/jre/lib/jfxswt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_162.jdk/Contents/Home/jre/lib/jsse.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_162.jdk/Contents/Home/jre/lib/management-agent.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_162.jdk/Contents/Home/jre/lib/plugin.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_162.jdk/Contents/Home/jre/lib/resources.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_162.jdk/Contents/Home/jre/lib/rt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_162.jdk/Contents/Home/lib/ant-javafx.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_162.jdk/Contents/Home/lib/dt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_162.jdk/Contents/Home/lib/javafx-mx.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_162.jdk/Contents/Home/lib/jconsole.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_162.jdk/Contents/Home/lib/packager.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_162.jdk/Contents/Home/lib/sa-jdi.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_162.jdk/Contents/Home/lib/tools.jar:/Users/fabian/projects/coroutinetest/out/production/classes:/Users/fabian/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib-jdk8/1.2.31/50094b02ec8a4c2e4444073c722bb56c8a52b83c/kotlin-stdlib-jdk8-1.2.31.jar:/Users/fabian/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlinx/kotlinx-coroutines-core/0.22.5/a654b6962cbdf394cd88e6fc173314c92dd50edb/kotlinx-coroutines-core-0.22.5.jar:/Users/fabian/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib-jdk7/1.2.31/95d6a67e8787280a82a2059e54e4db7ac6cfe74/kotlin-stdlib-jdk7-1.2.31.jar:/Users/fabian/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib/1.2.31/153dcd9ed9db246a7e36f4d7609e2a9f4718c674/kotlin-stdlib-1.2.31.jar:/Users/fabian/.gradle/caches/modules-2/files-2.1/org.jetbrains/annotations/13.0/919f0dfe192fb4e063e7dacadee7f8bb9a2672a9/annotations-13.0.jar MainKt
A
B
Exception in thread "ForkJoinPool.commonPool-worker-2" java.lang.RuntimeException: foobar
	at MainKt$main$job$1$1.doResume(Main.kt:11)
	at kotlin.coroutines.experimental.jvm.internal.CoroutineImpl.resume(CoroutineImpl.kt:54)
	at kotlinx.coroutines.experimental.DispatchedTask$DefaultImpls.run(Dispatched.kt:161)
	at kotlinx.coroutines.experimental.DispatchedContinuation.run(Dispatched.kt:25)
	at java.util.concurrent.ForkJoinTask$RunnableExecuteAction.exec(ForkJoinTask.java:1402)
	at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
	at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)
	at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)
	at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)
Exception in thread "ForkJoinPool.commonPool-worker-2" java.lang.RuntimeException: foobar
	at MainKt$main$job$1$1.doResume(Main.kt:11)
	at kotlin.coroutines.experimental.jvm.internal.CoroutineImpl.resume(CoroutineImpl.kt:54)
	at kotlinx.coroutines.experimental.DispatchedTask$DefaultImpls.run(Dispatched.kt:161)
	at kotlinx.coroutines.experimental.DispatchedContinuation.run(Dispatched.kt:25)
	at java.util.concurrent.ForkJoinTask$RunnableExecuteAction.exec(ForkJoinTask.java:1402)
	at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
	at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)
	at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)
	at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)
java.lang.RuntimeException: foobar
	at MainKt$main$job$1$1.doResume(Main.kt:11)
	at kotlin.coroutines.experimental.jvm.internal.CoroutineImpl.resume(CoroutineImpl.kt:54)
	at kotlinx.coroutines.experimental.DispatchedTask$DefaultImpls.run(Dispatched.kt:161)
	at kotlinx.coroutines.experimental.DispatchedContinuation.run(Dispatched.kt:25)
	at java.util.concurrent.ForkJoinTask$RunnableExecuteAction.exec(ForkJoinTask.java:1402)
	at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
	at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)
	at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)
	at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)
	Suppressed: kotlinx.coroutines.experimental.JobCancellationException: Job is being cancelled; job=StandaloneCoroutine{Cancelled}@44bf0252
		at kotlinx.coroutines.experimental.JobSupport.toCancellationException(Job.kt:788)
		at kotlinx.coroutines.experimental.JobSupport.getCancellationException(Job.kt:778)
		at kotlinx.coroutines.experimental.Child.invoke(Job.kt:1486)
		at kotlinx.coroutines.experimental.JobSupport.notifyCancellation(Job.kt:1534)
		at kotlinx.coroutines.experimental.JobSupport.tryMakeCancelling(Job.kt:1020)
		at kotlinx.coroutines.experimental.JobSupport.makeCancelling(Job.kt:1005)
		at kotlinx.coroutines.experimental.JobSupport.cancel(Job.kt:960)
		at kotlinx.coroutines.experimental.AbstractCoroutine.cancel(AbstractCoroutine.kt:174)
		at kotlinx.coroutines.experimental.CoroutineExceptionHandlerKt.handleCoroutineException(CoroutineExceptionHandler.kt:45)
		at kotlinx.coroutines.experimental.StandaloneCoroutine.onFinishingInternal$kotlinx_coroutines_core(Builders.kt:197)
		at kotlinx.coroutines.experimental.JobSupport.makeCompletingInternal(Job.kt:1083)
		at kotlinx.coroutines.experimental.JobSupport.makeCompletingOnce$kotlinx_coroutines_core(Job.kt:1045)
		at kotlinx.coroutines.experimental.AbstractCoroutine.resumeWithException(AbstractCoroutine.kt:118)
		at kotlin.coroutines.experimental.jvm.internal.CoroutineImpl.resume(CoroutineImpl.kt:53)
		... 7 more
	[CIRCULAR REFERENCE:java.lang.RuntimeException: foobar]

Process finished with exit code 0

@qwwdfsad qwwdfsad added the bug label Mar 28, 2018
@qwwdfsad
Copy link
Collaborator

qwwdfsad commented Mar 28, 2018

Good catch.
The problem here is that outer launch is cancelled due to inner launch exception, but for its completion handler we'd like to expose original exception from inner launch, thus suppressing JobCancellationException.

As solution we can either try to do something similar to reactor Exception#addThrowable (wrap multiple exceptions into CompositeException) or carefully revisit dependent cancellation paths

@qwwdfsad
Copy link
Collaborator

Verified, it crashes logback and it's not going to be fixed: https://jira.qos.ch/browse/LOGBACK-1027

@qwwdfsad
Copy link
Collaborator

qwwdfsad commented Jun 8, 2018

This specific case was fixed in 0.23 as part of #323

@qwwdfsad qwwdfsad closed this as completed Jun 8, 2018
@FabianFrank
Copy link
Author

Thank you for shipping a fix! 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants