Skip to content

Bug: aborting a queued Mutex/Semaphore waiter exactly as it is dequeued permanently leaks the lock/permit — eventual deadlock of connect/signing #389

Description

@Jaydbrown

File: contexts/WalletContext.tsxMutex.acquire (:56-87), Semaphore.acquire (:116-146)

When a queued waiter is dequeued by _release(), its resolver first checks the
abort signal:

// Semaphore
resolver: (release) => {
  if (signal?.aborted) { reject(new Error('Operation aborted')); return; }  // <-- no release
  resolve(release);
},

_release() has already shift()ed this entry off the queue and has not
incremented _available / cleared _locked (it delegated that to the resolver
by handing over release). The resolver rejects instead of resolving, so
release is never called.

Impact

If an AbortSignal fires in the exact window between "waiter is at the head of
the queue" and "_release dequeues and invokes it", that permit / the mutex lock
is lost forever. After maxConcurrentOperations such races the semaphore is
permanently exhausted and every subsequent signTx hangs; for the Mutex,
connect deadlocks.

Suggested fix

On the abort-at-dequeue path, still release: call the passed release() (or
this._release() / this._available++) before reject.

Activity

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

Metadata

Metadata

Assignees

Labels

Stellar WaveIssues in the Stellar wave programbugSomething isn't workingpriority: highSignificant bug or missing guard

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions