GitHub
CERT Secure Coding

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

Tool

Version

Checker

Description

CodeSonar
9.1p0

CONCURRENCY.TL

Try-lock that will never succeed

Helix QAC

2025.2

C++4986, C++4987


Parasoft C/C++test

2025.2

CERT_CPP-CON56-a

Avoid double locking

Polyspace Bug Finder

R2025b

CERT C++: CON56-CPP

Checks 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"