Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Added new rule (built from a copy of a previous rule).

UNDER CONStRUCTION

Mutexes that are used to protect shared data structures being concurrently accessed. If a mutex is destroyed while a thread is blocked waiting for that mutex, critical sections (shared data that would otherwise be protected from data races) are no longer protected.

The C++ Standard, [thread.mutex.class], paragraph 5 [ISO/IEC 14882-2014], states:

The behavior of a program is undefined if it destroys a mutex object owned by any thread or a thread terminates while owning a mutex object.

accesses to shared data may be locked using the lock() member function, and unlocked using the unlock() member function. If an exception occurs between the call to lock() and the call to unlock(), and the exception changes control flow such that unlock() is not called, the mutex will be left in the locked state and no critical sections protected by that mutex will be allowed to execute.  This is likely to lead to deadlock.

C++ supplies a lock_guard class that can be initialized with a mutex.  In its constructor, a lock_guard object locks the mutex, and in its destructor, it unlocks the mutex.  If an exception occurs and takes control flow out of the scope of the lock_guard object, its destructor will unlock the mutex and the program can continue working normally.

Mutexes should always be locked with a lock_guard object to protect against unanticipated control flow caused by exceptionsThis statement implies that destroying a mutex while a thread is waiting on it is undefined behavior.

Noncompliant Code Example

This noncompliant code example creates several threads that each invoke the do_work() function, passing a unique number as an ID.

...

manipulates shared data and protects the critical section by locking the mutex.  When it is finished, it unlocks the mutex.

However, if an exception occurs while manipulating the shared data, the mutex will remain locked.

Code Block
bgColor#ffcccc
langc
#include <mutex>
#include <thread>

constvoid sizemanipulate_t max_threads = 10;

void do_work(size_t i, shared_data(std::mutex *lockppm)
{
  std::lock_guard<std::mutex> guard(*lockppm->lock();

  // AccessPerform datawork protectedon byshared the lockdata.
}

void start_threads(void)
{
  std::thread threads[max_threads];
  std::mutex lock;

  for (size_t i = 0; i < max_threads; ++i) {
    threads[i] = std::thread(do_work, i, &lock);
  } pm->unlock();
}

Compliant Solution

This compliant solution eliminates the race condition by extending the lifetime of the lock:

Code Block
bgColor#ccccff
langc
#include <mutex>
#include <thread>

const size_t max_threads = 10;

void do_work(size_t i, std::mutex *lockp)
{
  std::lock_guard<std::mutex> guard(*lockp);

  // Access data protected by the lock.
}

std::mutex lock;

void start_threads(void)
{
  std::thread threads[max_threads];

  for (size_t i = 0; i < max_threads; ++i) {
    threads[i] = std::thread(do_work, i, &lock);
  }
}

Compliant Solution

This compliant solution eliminates the race condition by joining the threads before the lock's destructor is invoked:uses a lock_guard object to ensure that the mutex will be unlocked even if an exception occurs.

Code Block
bgColor#ccccff
langc
#include <mutex>
#include <thread>

constvoid sizemanipulate_t max_threads = 10;

void do_work(size_t i, shared_data(std::mutex *lockppm)
{
  std::lock_guard<std::mutex> guard(*lockppm);

  // Access data protected by the lock.
}
void run_threads(void)
{
  std::thread threads[max_threads];
  std::mutex lock;

  for (size_t i = 0; i < max_threads; ++i) {
    threads[i] = std::thread(do_work, i, &lock);
  }

  for (size_t i = 0; i < max_threads; ++i) {
    threads[i].join();
  }
}

Risk Assessment

Perform work on shared data.
}

Risk Assessment

If an exception occurs while a mutex is locked, deadlock may resultDestroying a mutex while it is locked may result in invalid control flow and data corruption.

Rule

Severity

Likelihood

Remediation Cost

Priority

Level

CON50CON51-CPP

MediumLow

Probable

HighLow

P4P6

L3L2

Automated Detection

Tool

Version

Checker

Description

 

 

Fortify SCA

5.0 

Can detect violations of this rule with CERT C Rule Pack

 
   Parasoft C/C++test9.5BD-RES-FREE, BD-RES-INVFREE 

Related Vulnerabilities

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

...

MITRE CWECWE-667, Improper Locking

Bibliography

[ISO/IEC 9899:201114882-2014]7.26.4.1, "The mtx_destroy Function[thread.lock] "Locks"

 

...