Documentation menu

Back to matching rules

Guard is held across a disallowed await

Rule ID: concurrency.guard-held-across-suspension@1.0.0. Availability below refers to source-scan at product 524fa07e.

V-ASYNC-14 — Guard is held across a disallowed await#

Holding a synchronous guard across an await can violate its allowed suspension or thread-affinity contract and prevent other work from making progress.

Availability#

Selected by default in source-scan. Selection does not mean a supported observation exists in your program.

Use the terminal from Installation, with ANALYZER set. Replace <package> and <product> with your supported package path and product name.

text
"$ANALYZER" source-scan --package-path <package> --product <product> --allow-build

Example and action#

Reproduced as part of the first-analysis package at product 524fa07e on Apple Swift 6.3.3, macOS arm64. Read the complete example before running it.

swift
import Foundation
private let gate = NSLock()
private func enter() { gate.lock() }
private func leave() { gate.unlock() }
func perform() async { enter(); await Task.yield(); leave() }

The control releases the guard before suspension. In a real application, copy the necessary state under the guard and revalidate it before applying a later result. Moving release is not safe if the operation requires a stronger state protocol.

swift
import Foundation
private let gate = NSLock()
private func enter() { gate.lock() }
private func leave() { gate.unlock() }
func perform() async { enter(); leave(); await Task.yield() }

Why this check works#

The check follows recognized guard acquisition, suspension and release events in an admitted trace. An acquired guard that survives the disallowed suspension supplies a witness. The tutorial produces one such finding and also an incomplete trace; both are preserved in the degraded report.

Assumptions and unknown#

The source mapper does not model every lock wrapper or synchronization primitive. Missing events, unclear guard identity or an incomplete trace preserve unknown. A witness in one trace does not establish completeness of another trace.

Evidence and interpretation#

Read condition coverage, observation counts and reasons in the actual report. A finding and an unknown observation can coexist. No observations is not a negative proof.

Historical evidence at 4558458d: recovery-required (historical qualification is incomplete and needs further evidence). That evidence has not been requalified for this product revision.

How we validate checks explains the evidence boundary. Foundations separates method assumptions from implementation claims.

Product 524fa07e · Historical catalog 4558458d
Experimental · Owner-provided checkout · Verified 2026-09-11

Read as MarkdownPage JSON

Report a documentation issue