Skip to content

Fix: [for cherry-picking] Removed the shared reentrancy-depth bypass by - #134

Closed
qodo-code-review[bot] wants to merge 2 commits into
cursor/raycast-storage-reset-and-lockfrom
fix/remediation-40f57668-883ca2
Closed

Fix: [for cherry-picking] Removed the shared reentrancy-depth bypass by#134
qodo-code-review[bot] wants to merge 2 commits into
cursor/raycast-storage-reset-and-lockfrom
fix/remediation-40f57668-883ca2

Conversation

@qodo-code-review

@qodo-code-review qodo-code-review Bot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Fixed Findings

  • Remove reentrant lock bypass
  • Bound write lock acquisition
  • Keep transfer result type private
  • Document Raycast backup and locking

Automated fix from agentic review of #133

Qodo Logo


Summary by cubic

Removed the reentrant write-lock bypass in Raycast storage and added a 5s lock acquisition timeout to prevent deadlocks. Tightened write paths and clarified the durable backup used by reset/restore.

  • Bug Fixes
    • Replaced the re-entrant writeDepth gate with an exclusive withWriteLock bounded to 5000 ms (warns and errors on timeout).
    • Routed all mutations through the lock: added saveUnlocked/flushRecentWritesUnlocked for internal calls; public save/flushRecentWrites now wrap with the lock.
    • Made StorageTransferResult internal and updated docs to describe the bounded lock and the reset-all durable backup/restore behavior.

Written for commit ae83fd8. Summary will update on new commits.

Review in cubic

- Remove reentrant lock bypass
- Bound write lock acquisition
- Keep transfer result type private

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 2 issues

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="QuickShell.Raycast/src/lib/storage.ts" line_range="660-661" />
<code_context>
-   * Runs `operation` exclusively against other writers.
-   * Re-entrant so nested save/flush calls from an outer mutator do not deadlock.
-   */
+  /** Runs `operation` exclusively against other writers, with bounded acquisition. */
   private async withWriteLock<T>(operation: () => Promise<T>): Promise<T> {
-    if (this.writeDepth > 0) {
-      return operation();
</code_context>
<issue_to_address>
**issue (bug_risk):** Dropping re-entrancy on the write lock introduces a deadlock risk if future code accidentally calls locked APIs from inside a locked section.

The previous `writeDepth` logic allowed nested `save`/`flush` calls without blocking. Now, correctness depends on always using `saveUnlocked`/`flushRecentWritesUnlocked` inside `withWriteLock`. A future nested call to `save` or `flushRecentWrites` from within `withWriteLock` would queue behind the current lock and then wait on itself, causing a deadlock until timeout. Please either reintroduce a re-entrancy mechanism (e.g., per-instance depth/flag that bypasses the queue) or add runtime assertions that prevent calling the locked variants from within `withWriteLock`, so misuse fails fast.
</issue_to_address>

### Comment 2
<location path="docs/architecture/parity-matrix.md" line_range="44" />
<code_context>
 | Import / export JSON | Full | Via settings / shared file | Full (extension import-export) | Desktop shares one file; Raycast is separate blob; import always untrusted |
 | Layout undo / redo | Full | Partial (plugin + editor) | Full (storage history) | |
 | Section separators | Full | Partial | Full (Raycast-local `layoutEntries`) | Desktop shared layout file; Raycast blob parallel |
+| Reset all / backup restore | Full | Partial | Full (durable Raycast backup) | Raycast backup is local to the extension and survives restart; mutations are serialized |

 ---
</code_context>
<issue_to_address>
**nitpick (typo):** Consider aligning the spelling of "reset-all" across documentation for consistency.

Elsewhere this flow is referred to as "reset-all" (hyphenated). Please update this row to match that spelling so the feature name is consistent across the docs.
</issue_to_address>

Fix all in Cursor


Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment on lines +660 to 661
/** Runs `operation` exclusively against other writers, with bounded acquisition. */
private async withWriteLock<T>(operation: () => Promise<T>): Promise<T> {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (bug_risk): Dropping re-entrancy on the write lock introduces a deadlock risk if future code accidentally calls locked APIs from inside a locked section.

The previous writeDepth logic allowed nested save/flush calls without blocking. Now, correctness depends on always using saveUnlocked/flushRecentWritesUnlocked inside withWriteLock. A future nested call to save or flushRecentWrites from within withWriteLock would queue behind the current lock and then wait on itself, causing a deadlock until timeout. Please either reintroduce a re-entrancy mechanism (e.g., per-instance depth/flag that bypasses the queue) or add runtime assertions that prevent calling the locked variants from within withWriteLock, so misuse fails fast.

Fix in Cursor

| Import / export JSON | Full | Via settings / shared file | Full (extension import-export) | Desktop shares one file; Raycast is separate blob; import always untrusted |
| Layout undo / redo | Full | Partial (plugin + editor) | Full (storage history) | |
| Section separators | Full | Partial | Full (Raycast-local `layoutEntries`) | Desktop shared layout file; Raycast blob parallel |
| Reset all / backup restore | Full | Partial | Full (durable Raycast backup) | Raycast backup is local to the extension and survives restart; mutations are serialized |

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpick (typo): Consider aligning the spelling of "reset-all" across documentation for consistency.

Elsewhere this flow is referred to as "reset-all" (hyphenated). Please update this row to match that spelling so the feature name is consistent across the docs.

Fix in Cursor

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.

0 participants