Skip to content

Commit 33d85f4

Browse files
committed
Protect isDispatchNeeded calls
1 parent 8a494e9 commit 33d85f4

File tree

7 files changed

+30
-22
lines changed

7 files changed

+30
-22
lines changed

kotlinx-coroutines-core/common/src/CoroutineDispatcher.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,7 @@ public abstract class CoroutineDispatcher :
192192
* @suppress **This an internal API and should not be used from general code.**
193193
*/
194194
@InternalCoroutinesApi
195-
public open fun dispatchYield(context: CoroutineContext, block: Runnable): Unit = dispatch(context, block)
195+
public open fun dispatchYield(context: CoroutineContext, block: Runnable): Unit = safeDispatch(context, block)
196196

197197
/**
198198
* Returns a continuation that wraps the provided [continuation], thus intercepting all resumptions.

kotlinx-coroutines-core/common/src/Yield.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ public suspend fun yield(): Unit = suspendCoroutineUninterceptedOrReturn sc@ { u
2626
val context = uCont.context
2727
context.ensureActive()
2828
val cont = uCont.intercepted() as? DispatchedContinuation<Unit> ?: return@sc Unit
29-
if (cont.dispatcher.isDispatchNeeded(context)) {
29+
if (cont.dispatcher.safeIsDispatchNeeded(context)) {
3030
// this is a regular dispatcher -- do simple dispatchYield
3131
cont.dispatchYield(context, Unit)
3232
} else {

kotlinx-coroutines-core/common/src/internal/DispatchedContinuation.kt

+18-10
Original file line numberDiff line numberDiff line change
@@ -188,10 +188,10 @@ internal class DispatchedContinuation<in T>(
188188
override fun resumeWith(result: Result<T>) {
189189
val context = continuation.context
190190
val state = result.toState()
191-
if (dispatcher.isDispatchNeeded(context)) {
191+
if (dispatcher.safeIsDispatchNeeded(context)) {
192192
_state = state
193193
resumeMode = MODE_ATOMIC
194-
dispatchWithExceptionHandling(context)
194+
dispatcher.safeDispatch(context, this)
195195
} else {
196196
executeUnconfined(state, MODE_ATOMIC) {
197197
withCoroutineContext(this.context, countOrElement) {
@@ -209,10 +209,10 @@ internal class DispatchedContinuation<in T>(
209209
noinline onCancellation: ((cause: Throwable) -> Unit)?
210210
) {
211211
val state = result.toState(onCancellation)
212-
if (dispatcher.isDispatchNeeded(context)) {
212+
if (dispatcher.safeIsDispatchNeeded(context)) {
213213
_state = state
214214
resumeMode = MODE_CANCELLABLE
215-
dispatchWithExceptionHandling(context)
215+
dispatcher.safeDispatch(context, this)
216216
} else {
217217
executeUnconfined(state, MODE_CANCELLABLE) {
218218
if (!resumeCancelled(state)) {
@@ -260,13 +260,21 @@ internal class DispatchedContinuation<in T>(
260260

261261
override fun toString(): String =
262262
"DispatchedContinuation[$dispatcher, ${continuation.toDebugString()}]"
263+
}
263264

264-
private fun dispatchWithExceptionHandling(context: CoroutineContext) {
265-
try {
266-
dispatcher.dispatch(context, this)
267-
} catch (e: Throwable) {
268-
throw DispatchException(e, dispatcher, context)
269-
}
265+
internal fun CoroutineDispatcher.safeDispatch(context: CoroutineContext, runnable: Runnable) {
266+
try {
267+
dispatch(context, runnable)
268+
} catch (e: Throwable) {
269+
throw DispatchException(e, this, context)
270+
}
271+
}
272+
273+
internal fun CoroutineDispatcher.safeIsDispatchNeeded(context: CoroutineContext): Boolean {
274+
try {
275+
return isDispatchNeeded(context)
276+
} catch (e: Throwable) {
277+
throw DispatchException(e, this, context)
270278
}
271279
}
272280

kotlinx-coroutines-core/common/src/internal/DispatchedTask.kt

+3-3
Original file line numberDiff line numberDiff line change
@@ -157,8 +157,8 @@ internal fun <T> DispatchedTask<T>.dispatch(mode: Int) {
157157
// dispatch directly using this instance's Runnable implementation
158158
val dispatcher = delegate.dispatcher
159159
val context = delegate.context
160-
if (dispatcher.isDispatchNeeded(context)) {
161-
dispatcher.dispatch(context, this)
160+
if (dispatcher.safeIsDispatchNeeded(context)) {
161+
dispatcher.safeDispatch(context, this)
162162
} else {
163163
resumeUnconfined()
164164
}
@@ -223,7 +223,7 @@ internal inline fun Continuation<*>.resumeWithStackTrace(exception: Throwable) {
223223
/**
224224
* This exception holds an exception raised in [CoroutineDispatcher.dispatch] method
225225
*
226-
* @see DispatchedContinuation.dispatchWithExceptionHandling
226+
* @see safeDispatch
227227
*/
228228
internal class DispatchException(
229229
override val cause: Throwable,

kotlinx-coroutines-core/common/src/internal/LimitedDispatcher.kt

+3-3
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ internal class LimitedDispatcher(
4242

4343
override fun dispatch(context: CoroutineContext, block: Runnable) {
4444
dispatchInternal(block) { worker ->
45-
dispatcher.dispatch(this, worker)
45+
dispatcher.safeDispatch(this, worker)
4646
}
4747
}
4848

@@ -116,10 +116,10 @@ internal class LimitedDispatcher(
116116
}
117117
currentTask = obtainTaskOrDeallocateWorker() ?: return
118118
// 16 is our out-of-thin-air constant to emulate fairness. Used in JS dispatchers as well
119-
if (++fairnessCounter >= 16 && dispatcher.isDispatchNeeded(this@LimitedDispatcher)) {
119+
if (++fairnessCounter >= 16 && dispatcher.safeIsDispatchNeeded(this@LimitedDispatcher)) {
120120
// Do "yield" to let other views execute their runnable as well
121121
// Note that we do not decrement 'runningWorkers' as we are still committed to our part of work
122-
dispatcher.dispatch(this@LimitedDispatcher, this)
122+
dispatcher.safeDispatch(this@LimitedDispatcher, this)
123123
return
124124
}
125125
}

kotlinx-coroutines-core/common/src/internal/NamedDispatcher.kt

+2-2
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@ internal class NamedDispatcher(
1212
private val name: String
1313
) : CoroutineDispatcher(), Delay by (dispatcher as? Delay ?: DefaultDelay) {
1414

15-
override fun isDispatchNeeded(context: CoroutineContext): Boolean = dispatcher.isDispatchNeeded(context)
15+
override fun isDispatchNeeded(context: CoroutineContext): Boolean = dispatcher.safeIsDispatchNeeded(context)
1616

17-
override fun dispatch(context: CoroutineContext, block: Runnable) = dispatcher.dispatch(context, block)
17+
override fun dispatch(context: CoroutineContext, block: Runnable) = dispatcher.safeDispatch(context, block)
1818

1919
@InternalCoroutinesApi
2020
override fun dispatchYield(context: CoroutineContext, block: Runnable) = dispatcher.dispatchYield(context, block)

kotlinx-coroutines-core/jvm/src/Executors.kt

+2-2
Original file line numberDiff line numberDiff line change
@@ -106,8 +106,8 @@ public fun CoroutineDispatcher.asExecutor(): Executor =
106106

107107
private class DispatcherExecutor(@JvmField val dispatcher: CoroutineDispatcher) : Executor {
108108
override fun execute(block: Runnable) {
109-
if (dispatcher.isDispatchNeeded(EmptyCoroutineContext)) {
110-
dispatcher.dispatch(EmptyCoroutineContext, block)
109+
if (dispatcher.safeIsDispatchNeeded(EmptyCoroutineContext)) {
110+
dispatcher.safeDispatch(EmptyCoroutineContext, block)
111111
} else {
112112
block.run()
113113
}

0 commit comments

Comments
 (0)