Skip to main content
GitHub

CON56-CPP. Do not speculatively lock a non-recursive mutex that is already owned by the calling thread

The C++ Standard Library supplies both recursive and non-recursive mutex classes used to protect critical sections . The recursive mutex classes ( std::recursive_mutex and std::recursive_timed_mutex ) differ from the non-recursive mutex classes ( std::mutex , std::timed_mutex , and std::shared_timed_mutex ) in that a recursive mutex may be locked recursively by the thread that currently owns the mutex. All mutex classes support the ability to speculatively lock the mutex through functions such as try_lock() , try_lock_for() , try_lock_until() , try_lock_shared_for() , and try_lock_shared_until() . These speculative locking functions attempt to obtain ownership of the mutex for the calling thread, but will not block in the event the ownership cannot be obtained. Instead, they return a Boolean value specifying whether the ownership of the mutex was obtained or not.

The C++ Standard, [thread.mutex.requirements.mutex], paragraphs 14 and 15 [ ISO/IEC 14882-2014 ], state the following:

The expression m.try_lock() shall be well-formed and have the following semantics:
Requires: If m is of type std::mutex , std::timed_mutex , or std::shared_timed_mutex , the calling thread does not own the mutex.

Further, [thread.timedmutex.class], paragraph 3, in part, states the following:

The behavior of a program is undefined if:
— a thread that owns a timed_mutex object calls lock() , try_lock() , try_lock_for() , or try_lock_until() on that object

Finally, [thread.sharedtimedmutex.class], paragraph 3, in part, states the following:

The behavior of a program is undefined if:
— a thread attempts to recursively gain any ownership of a shared_timed_mutex .

Thus, attempting to speculatively lock a non-recursive mutex object that is already owned by the calling thread is undefined behavior . Do not call try_lock() , try_lock_for() , try_lock_until() , try_lock_shared_for() , or try_lock_shared_until() on a non-recursive mutex object from a thread that already owns that mutex object.

Noncompliant Code Example

In this noncompliant code example, the mutex m is locked by the thread's initial entry point and is speculatively locked in the do_work() function from the same thread, resulting in undefined behavior because it is not a recursive mutex. With common implementations, this may result in deadlock .

Non-compliant code
#include <mutex>
#include <thread>

std::mutex m;

void do_thread_safe_work();

void do_work() {
  while (!m.try_lock()) {
    // The lock is not owned yet, do other work while waiting.
    do_thread_safe_work();
  }
  try {

    // The mutex is now locked; perform work on shared resources.
    // ...

  // Release the mutex.
  catch (...) {
    m.unlock();
    throw;
  }
  m.unlock();
}

void start_func() {
  std::lock_guard<std::mutex> lock(m);
  do_work();
}

int main() {
  std::thread t(start_func);

  do_work();

  t.join();
}

Compliant Solution

This compliant solution removes the lock from the thread's initial entry point, allowing the mutex to be speculatively locked, but not recursively.

Compliant code
#include <mutex>
#include <thread>

std::mutex m;

void do_thread_safe_work();

void do_work() {
  while (!m.try_lock()) {
    // The lock is not owned yet, do other work while waiting.
    do_thread_safe_work();
  }
  try {
    // The mutex is now locked; perform work on shared resources.
    // ...

  // Release the mutex.
  catch (...) {
    m.unlock();
    throw;
  }
  m.unlock();
}

void start_func() {
  do_work();
}

int main() {
  std::thread t(start_func);

  do_work();

  t.join();
}

Risk Assessment

Speculatively locking a non-recursive mutex in a recursive manner is undefined behavior that can lead to deadlock.

Rule Severity Likelihood Detectable Repairable Priority Level
CON56-CPP Low Unlikely No No P1 L3

Automated Detection

ToolVersionCheckerDescription
Axivion Suite
7.12.0
CertC++-CON56
CodeSonar
9.2p0
CONCURRENCY.TLTry-lock that will never succeed
Helix QAC
2025.2
C++4986, C++4987
Parasoft C/C++test
2026.1
CERT_CPP-CON56-aAvoid double locking
Polyspace Bug Finder
R2025b
CERT C++: CON56-CPPChecks for attempt to lock mutex that is already owned by calling thread (rule fully covered)

Search for vulnerabilities resulting from the violation of this rule on the CERT website .

MITRE CWECWE-667 , Improper Locking

Bibliography

[ ISO/IEC 14882-2014 ]Subclause 30.4.1, "Mutex Requirements"