Skip to content

Cooperative Thread - MRE Crasher#272

Closed
baksha97 wants to merge 2 commits intookta:masterfrom
baksha97:travis/coop-crasher
Closed

Cooperative Thread - MRE Crasher#272
baksha97 wants to merge 2 commits intookta:masterfrom
baksha97:travis/coop-crasher

Conversation

@baksha97
Copy link
Copy Markdown

@baksha97 baksha97 commented Mar 27, 2026

Problem Analysis (Technical)

The SDK's withIsolationSyncThrowing and withIsolationSync functions (CommonSupport/ExpressionUtilities.swift) bridge synchronous code to actor-isolated code by spawning a Task and blocking on DispatchGroup.wait(). When called from a Swift Concurrency cooperative thread — i.e. inside any async function, Task, or actor-isolated context — group.wait() blocks that cooperative thread while the inner Task also needs a cooperative thread to execute (to hop to @CredentialActor). Once the pool is saturated, neither side can make progress, and the process deadlocks.

The most direct path is Credential.revoke(type:), which is itself async and calls withIsolationSyncThrowing at L285 — guaranteeing the call originates on the cooperative pool. The remaining 5 withIsolationSyncThrowing call sites and 22 withIsolationSync call sites are synchronous but deadlock when any caller happens to be on the cooperative pool.

Solution (Technical)

This PR provides a detailed bug report with a self-contained reproduction (Sources/CooperativePoolDeadlock/main.swift) that exercises the real SDK modules to deterministically trigger the deadlock. Recommendation is to stick with a single consistent concurrency pattern.

Affected Components

  • CommonSupport/ExpressionUtilities.swiftwithIsolationSyncThrowing, withIsolationSync
  • AuthFoundation/Credential.swift — 6 withIsolationSyncThrowing call sites + 4 withIsolationSync call sites
  • AuthFoundation/CredentialCoordinatorImpl.swift, Authentication.swiftwithIsolationSync call sites
  • All AuthenticationFlow conformances (AuthorizationCodeFlow, DeviceAuthorizationFlow, JWTAuthorizationFlow, ResourceOwnerFlow, SessionTokenFlow, TokenExchangeFlow, DirectAuthFlow, InteractionCodeFlow, SessionLogoutFlow) — withIsolationSync in isAuthenticating/context property getters
  • All SDK 2.x versions (2.0.0 – 2.1.4) and master at 5c710b0

Steps to reproduce:

  1. Build the reproduction target:
    swift build --product CooperativePoolDeadlock \
      --sdk "$(xcrun --sdk iphonesimulator --show-sdk-path)" \
      --triple arm64-apple-ios13.0-simulator
  2. Boot a simulator and run with a single-thread cooperative pool:
    xcrun simctl boot "iPhone 16 Pro Max"
    SIMCTL_CHILD_LIBDISPATCH_COOPERATIVE_POOL_STRICT=1 \
      xcrun simctl spawn --standalone booted \
      .build/arm64-apple-ios-simulator/debug/CooperativePoolDeadlock

Actual result:

Process hangs for 5 seconds, prints DEADLOCK CONFIRMED, and exits with code 1. Under normal pool sizing (without the env var), the Swift runtime detects thread starvation and terminates with SIGTRAP or EXC_BAD_ACCESS — matching the production Crashlytics crash on com.apple.root.user-initiated-qos.cooperative.

Expected result:

Credential.revoke(), Credential.remove(), and other Credential APIs called from async contexts complete without deadlocking or crashing.

Tests

  • Sources/CooperativePoolDeadlock/main.swift — reproduction executable that imports CommonSupport and AuthFoundation, spawns concurrent Tasks calling withIsolationSyncThrowing with a @CredentialActor-isolated closure (mirroring Credential.revoke()remove()), and uses a 5-second watchdog to confirm the deadlock. Exits 1 on deadlock, 0 if the pool was not saturated.

@AlexNachbaur
Copy link
Copy Markdown
Contributor

Thank you for your very comprehensive issue and reproduction case. I've created a unit test that is able to consistently reproduce the problem you uncovered, and I've written a fix for this in #274. @baksha97 please feel free to review that pull request, or see if it is able to resolve the problem in your application.

@AlexNachbaur
Copy link
Copy Markdown
Contributor

Resolved in #274 and released in version 2.1.5.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants