Skip to content

Commit e559620

Browse files
committed
[Concurrency] Futher prevent crashes in legacy mode of isCurrentExecutor
1 parent c531f29 commit e559620

File tree

1 file changed

+36
-24
lines changed

1 file changed

+36
-24
lines changed

stdlib/public/Concurrency/Actor.cpp

Lines changed: 36 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,12 @@ static bool swift_task_isCurrentExecutorImpl(SerialExecutorRef expectedExecutor)
374374

375375
// To support old applications on apple platforms which assumed this call
376376
// does not crash, try to use a more compatible mode for those apps.
377+
//
378+
// We only allow returning `false` directly from this function when operating
379+
// in 'Legacy_NoCheckIsolated_NonCrashing' mode. If allowing crashes, we
380+
// instead must call into 'checkIsolated' or crash directly.
381+
//
382+
// Whenever we confirm an executor equality, we can return true, in any mode.
377383
static swift::once_t checkModeToken;
378384
swift::once(checkModeToken, checkIsCurrentExecutorMode, nullptr);
379385

@@ -425,40 +431,47 @@ static bool swift_task_isCurrentExecutorImpl(SerialExecutorRef expectedExecutor)
425431
// If the expected executor is a default actor, it makes no sense to try
426432
// the 'checkIsolated' call, it must be equal to the other actor, or it is
427433
// not the same isolation domain.
428-
swift_Concurrency_fatalError(0, "Incorrect actor executor assumption");
434+
if (isCurrentExecutorMode == Default_UseCheckIsolated_AllowCrash) {
435+
swift_Concurrency_fatalError(0, "Incorrect actor executor assumption");
436+
}
429437
return false;
430438
}
431439

432440
if (expectedExecutor.isMainExecutor() && !currentExecutor.isMainExecutor()) {
433-
// TODO: Invoke checkIsolated() on "main" SerialQueue once it implements `checkIsolated`, otherwise messages will be sub-par and hard to address
434-
swift_Concurrency_fatalError(0, "Incorrect actor executor assumption; Expected MainActor executor");
441+
if (isCurrentExecutorMode == Default_UseCheckIsolated_AllowCrash) {
442+
// TODO: Invoke checkIsolated() on "main" SerialQueue once it implements `checkIsolated`, for potentially better/more consistent error messages
443+
swift_Concurrency_fatalError(0, "Incorrect actor executor assumption; Expected MainActor executor");
444+
}
435445
return false;
436446
} else if (!expectedExecutor.isMainExecutor() && currentExecutor.isMainExecutor()) {
437-
// TODO: Invoke checkIsolated() on "main" SerialQueue once it implements `checkIsolated`, otherwise messages will be sub-par and hard to address
438-
swift_Concurrency_fatalError(0, "Incorrect actor executor assumption; Expected not-MainActor executor");
447+
if (isCurrentExecutorMode == Default_UseCheckIsolated_AllowCrash) {
448+
// TODO: Invoke checkIsolated() on "main" SerialQueue once it implements `checkIsolated`, for potentially better/more consistent error messages
449+
swift_Concurrency_fatalError(0, "Incorrect actor executor assumption; Expected not-MainActor executor");
450+
}
439451
return false;
440452
}
441453

442454
if (expectedExecutor.isComplexEquality()) {
443-
if (!swift_compareWitnessTables(
444-
reinterpret_cast<const WitnessTable*>(currentExecutor.getSerialExecutorWitnessTable()),
445-
reinterpret_cast<const WitnessTable*>(expectedExecutor.getSerialExecutorWitnessTable()))) {
446-
// different witness table, we cannot invoke complex equality call
447-
return false;
448-
}
449-
450-
// Avoid passing nulls to Swift for the isSame check:
451-
if (!currentExecutor.getIdentity() || !expectedExecutor.getIdentity()) {
452-
return false;
455+
if (currentExecutor.getIdentity() && expectedExecutor.getIdentity() &&
456+
swift_compareWitnessTables(
457+
reinterpret_cast<const WitnessTable *>(
458+
currentExecutor.getSerialExecutorWitnessTable()),
459+
reinterpret_cast<const WitnessTable *>(
460+
expectedExecutor.getSerialExecutorWitnessTable()))) {
461+
462+
auto isSameExclusiveExecutionContextResult =
463+
_task_serialExecutor_isSameExclusiveExecutionContext(
464+
currentExecutor.getIdentity(), expectedExecutor.getIdentity(),
465+
swift_getObjectType(currentExecutor.getIdentity()),
466+
expectedExecutor.getSerialExecutorWitnessTable());
467+
468+
// if the 'isSameExclusiveExecutionContext' returned true we trust
469+
// it and return; if it was false, we need to give checkIsolated another
470+
// chance to check.
471+
if (isSameExclusiveExecutionContextResult) {
472+
return true;
473+
}
453474
}
454-
455-
auto result = _task_serialExecutor_isSameExclusiveExecutionContext(
456-
currentExecutor.getIdentity(),
457-
expectedExecutor.getIdentity(),
458-
swift_getObjectType(currentExecutor.getIdentity()),
459-
expectedExecutor.getSerialExecutorWitnessTable());
460-
461-
return result;
462475
}
463476

464477
// This provides a last-resort check by giving the expected SerialExecutor the
@@ -488,7 +501,6 @@ static bool swift_task_isCurrentExecutorImpl(SerialExecutorRef expectedExecutor)
488501
return true;
489502
}
490503

491-
// Using legacy mode, if no explicit executor match worked, we assume `false`
492504
assert(isCurrentExecutorMode == Legacy_NoCheckIsolated_NonCrashing);
493505
return false;
494506
}

0 commit comments

Comments
 (0)