Repository navigation
Conversation
WP11_Lock_LockRO locked the write mutex for the first reader and WP11_Lock_UnlockRO unlocked it for the last reader, which is often a different thread. Unlocking a pthread mutex, or leaving a critical section, from a thread that does not own it is undefined behaviour. Under Wine pkcs11mtt hangs because of it, and ThreadSanitizer cannot track the lock at all. Rebuild the lock from one mutex and a condition variable, with a reader count and a writer flag. The mutex only guards the counters and is not held while the lock is held. The semantics are unchanged: a waiting writer does not block new readers, so a thread can take the read lock again while holding it. pthreads use pthread_mutex_t and pthread_cond_t; Windows (Vista and later) uses CRITICAL_SECTION and CONDITION_VARIABLE. The two-mutex lock remains as a fallback for other threading APIs.
Contributor
There was a problem hiding this comment.
🟡 Changes recommended
Canceling a blocked pthread waiter can leave the internal mutex locked and deadlock subsequent operations.
1 open finding
What changed in this PR
Reworks WP11_Lock to avoid cross-thread mutex releases when protecting global, slot, and token state.
Changes:
- Adds mutex-and-condition-variable locking for pthreads and supported Windows targets.
- Preserves nested read locking and documents the existing fallback’s limitations.
| File | Description |
|---|---|
| src/internal.c | Implements condition-variable locking while retaining fallback and single-threaded paths. |
🧠 Review effort: Balanced
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Member
Author
|
Superseded by #254, which now carries this fix as its own commit ("Stop releasing WP11_Lock from a thread that did not take it"), plus a follow-up commit for the Copilot cancellation finding here ("Keep WP11_Lock acquisition free of cancellation points"). |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

WP11_Lockis the reader/writer lock used for the global, slot and token state. Its read path locked thewritemutex for the first reader and unlocked it for the last reader, which is often a different thread. Releasing a pthread mutex, or leaving a critical section, from a thread that does not own it is undefined behaviour, and it shows:pkcs11mtthangs. With the old lock it hung until a timeout in 4 of 5 runs (master; master with the test harness fixed; and current code with only the lock switched back). With this change it passed 8 of 8.make checkreports hundreds of false races and lock-order inversions, even in single-threaded tests. This is part of why TSAN is disabled insanitizer-tests.yml; Fix WP11_Lock ownership and remaining TSAN races, enable TSAN in CI #254 re-enables it on top of this one.The lock is now one mutex plus a condition variable, with a reader count and a writer flag. The mutex only guards the counters and is never held while the lock is held. The semantics are unchanged: a waiting writer does not stop new readers, so a thread can take the read lock again while holding it (the old lock allowed that too, so no code path that nests read locks can deadlock).
WOLFSSL_PTHREADS):pthread_mutex_tandpthread_cond_t.USE_WINDOWS_API, Vista and later, not CE):CRITICAL_SECTIONandCONDITION_VARIABLE.SINGLE_THREADEDis unchanged.Testing:
make testpasses (debug and default configs); ASAN and TSANmake checkpass.concurrent_destroy_object_testandpkcs11mtt(5 runs each, old vs new library, same build): no measurable difference.InitializeConditionVariable/SleepConditionVariableCS/WakeAllConditionVariable, run under Wine: 58 pass, 4 skip, 0 fail,pkcs11mtt64/64. MSVC was not built locally; thewin-test.ymljobs on this PR cover it.