{"schemaVersion":"2.0.0","locale":"en","title":"Guard is held across a disallowed await","description":"Rule ID: concurrency.guard-held-across-suspension@1.0.0. Availability below refers to source-scan at product 524fa07e.","htmlUrl":"https://docs.swift-analyzer.com/catalog/concurrency.guard-held-across-suspension/","markdownUrl":"https://docs.swift-analyzer.com/catalog/concurrency.guard-held-across-suspension/index.md","productRevision":"524fa07e0ae4153c84ac12ae9eb6559df89ec2be","catalogRevision":"4558458d","docsRevision":"1f17ba58ab08627e0de898f1442067b09e960b48cd5605d6529e9275f8930d68","channel":"pre-prod","maturity":"experimental","access":"owner-provided-checkout","markdown":"# Guard is held across a disallowed await\n\nRule ID: concurrency.guard-held-across-suspension@1.0.0. Availability below refers to source-scan at product 524fa07e.\n\n## V-ASYNC-14 — Guard is held across a disallowed await\n\nHolding a synchronous guard across an await can violate its allowed suspension or thread-affinity contract and prevent other work from making progress.\n\n### Availability\n\nSelected by default in source-scan. Selection does not mean a supported observation exists in your program.\n\nUse the terminal from [Installation](https://docs.swift-analyzer.com/get-started/installation/), with ANALYZER set. Replace `<package>` and `<product>` with your supported package path and product name.\n\n```text\n\"$ANALYZER\" source-scan --package-path <package> --product <product> --allow-build\n```\n\n### Example and action\n\nReproduced as part of the first-analysis package at product 524fa07e on Apple Swift 6.3.3, macOS arm64. Read the [complete example](https://docs.swift-analyzer.com/get-started/first-analysis/) before running it.\n\n```swift\nimport Foundation\nprivate let gate = NSLock()\nprivate func enter() { gate.lock() }\nprivate func leave() { gate.unlock() }\nfunc perform() async { enter(); await Task.yield(); leave() }\n```\n\nThe 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.\n\n```swift\nimport Foundation\nprivate let gate = NSLock()\nprivate func enter() { gate.lock() }\nprivate func leave() { gate.unlock() }\nfunc perform() async { enter(); leave(); await Task.yield() }\n```\n\n### Why this check works\n\nThe 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.\n\n### Assumptions and unknown\n\nThe 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.\n\n### Evidence and interpretation\n\nRead 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.\n\nHistorical evidence at 4558458d: recovery-required (historical qualification is incomplete and needs further evidence). That evidence has not been requalified for this product revision.\n\n[How we validate checks](https://docs.swift-analyzer.com/concepts/validation/) explains the evidence boundary. [Foundations](https://docs.swift-analyzer.com/concepts/foundations/) separates method assumptions from implementation claims.\n","anchors":["guard-is-held-across-a-disallowed-await","V-ASYNC-14","availability","example-and-action","why-this-check-works","assumptions-and-unknown","evidence-and-interpretation"]}
