Mutexes Mutex objects are used to protect shared data structures from being concurrently accessed. If a mutex object is destroyed while a thread is blocked waiting for that mutexthe lock, critical sections and shared data are no longer protected.
The C++ Standard, [thread.mutex.class], paragraph 5 [ISO/IEC 14882-2014], states the following:
The behavior of a program is undefined if it destroys a
mutex
object owned by any thread or a thread terminates while owning amutex
object.
This statement implies Similar wording exists for std::recursive_mutex
, std::timed_mutex
, std::recursive_timed_mutex
, and std::shared_timed_mutex
. These statements imply that destroying a mutex object while a thread is waiting on it is undefined behavior.
...
Unfortunately, this code contains a race condition, allowing the mutex to be destroyed before while it is unlockedstill owned, because start_threads()
may invoke the lockmutex's destructor before all of the threads have finished using the lock. This behavior is undefined.exited.
Code Block | ||||
---|---|---|---|---|
| ||||
#include <mutex> #include <thread> const size_t max_threadsmaxThreads = 10; void do_work(size_t i, std::mutex *pm) { std::lock_guard<std::mutex> guardlk(*pm); // Access data protected by the lock. } void start_threads(void) { std::thread threads[max_threadsmaxThreads]; std::mutex m; for (size_t i = 0; i < max_threadsmaxThreads; ++i) { threads[i] = std::thread(do_work, i, &m); } } |
...
This compliant solution eliminates the race condition by extending the lifetime of the lock:mutex.
Code Block | ||||
---|---|---|---|---|
| ||||
#include <mutex> #include <thread> const size_t max_threadsmaxThreads = 10; void do_work(size_t i, std::mutex *pm) { std::lock_guard<std::mutex> guardlk(*pm); // Access data protected by the lock. } std::mutex m; void start_threads(void) { std::thread threads[max_threadsmaxThreads]; for (size_t i = 0; i < max_threadsmaxThreads; ++i) { threads[i] = std::thread(do_work, i, &m); } } |
...
This compliant solution eliminates the race condition by joining the threads before the mutex's destructor is invoked:.
Code Block | ||||
---|---|---|---|---|
| ||||
#include <mutex> #include <thread> const size_t max_threadsmaxThreads = 10; void do_work(size_t i, std::mutex *pm) { std::lock_guard<std::mutex> guardlk(*pm); // Access data protected by the lock. } void run_threads(void) { std::thread threads[max_threadsmaxThreads]; std::mutex m; for (size_t i = 0; i < max_threadsmaxThreads; ++i) { threads[i] = std::thread(do_work, i, &m); } for (size_t i = 0; i < max_threadsmaxThreads; ++i) { threads[i].join(); } } |
...
Destroying a mutex while it is locked may result in invalid control flow and data corruption.
Rule | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
CON50-CPP | Medium | Probable | High | P4 | L3 |
Automated Detection
Tool | Version | Checker | Description |
---|
CodeSonar |
| CONCURRENCY.LOCALARG | Local Variable Passed to Thread | ||||||
Helix QAC |
| DF961, DF4962 | |||||||
Klocwork |
| CERT.CONC.MUTEX.DESTROY_WHILE_LOCKED | |||||||
Parasoft C/C++test |
| CERT_CPP-CON50-a | Do not destroy another thread's mutex | ||||||
Polyspace Bug Finder |
| CERT C++: CON50-CPP | Checks for destruction of locked mutex (rule partially covered) |
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
Related Guidelines
MITRE CWE | CWE-667, Improper Locking |
SEI CERT C Coding Standard | CON31-C. Do not destroy a mutex while it is locked |
Bibliography
[ISO/IEC 14882-2014] |
Subclause 30.4.1, "Mutex Requirements" |
...