CERT.CONC.LOCK.NO_RELEASE_ON_EXCEPTION

Ensure actively held locks are released on exceptional conditions

This checker is applicable only to the modern engine.

CERT.CONC.LOCK.NO_RELEASE_ON_EXCEPTION implements CERT C++ rule CON51-CPP. It reports mutexes that are manually locked but not guaranteed to be unlocked on all execution paths. A mutex left locked after an exception or early exit can lead to deadlocks.

Mitigation and prevention

Prefer RAII lock-ownership wrappers such as std::lock_guard, std::unique_lock, and std::shared_lock instead of manually calling lock() and unlock(). These wrappers automatically release the mutex when the object goes out of scope, ensuring that the lock is released on all exit paths, including exceptions and early returns.

If manual locking is required, ensure that every execution path releases the mutex before the function exits. In particular, exception paths must not bypass the corresponding unlock() call. Failure to release a mutex on all paths can leave it permanently locked and lead to deadlocks.

Vulnerable code example

Copy
#include <mutex>

void manipulate_shared_data(std::mutex &pm) {
  pm.lock();          // CERT.CONC.LOCK.NO_RELEASE_ON_EXCEPTION
  // ... work on shared data that may throw ...
}                     // pm is still locked on every exit

A mutex locked manually with no unlock() before the function returns. If the work throws, the mutex is never released.

Fixed code example 1 (preferred: RAII)

Copy
#include <mutex>

void manipulate_shared_data(std::mutex &pm) {
  std::lock_guard<std::mutex> guard(pm);
  // ... work on shared data ...
}                     // guard's destructor unlocks on every exit, incl. exceptions

Fixed code example 2 (manual unlock)

Copy
#include <mutex>

void manipulate_shared_data(std::mutex &pm) {
  pm.lock();
  try {
    // ... work on shared data ...
  } catch (...) {
    pm.unlock();
    throw;
  }
  pm.unlock();
}

Note: the current flow-insensitive checker accepts example 2 because an unlock() is present in the function; it does not verify that the catch path actually unlocks. This is adequate for the standard manual-unlock idiom but is a source of potential false negatives.

Limitations

The CERT.CONC.LOCK.NO_RELEASE_ON_EXCEPTION checker uses a simplified analysis that does not fully model exception handling or control flow. It supports only simple mutex object tracking within a single function, may generate duplicate reports for some lambda expressions, and currently supports only std mutex APIs.

External guidance