You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 12 Next »

Mutexes are used to protect shared data structures from being concurrently accessed. If a mutex is destroyed while a thread is blocked waiting for that mutex, critical sections and shared data 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.

This 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.

#include <mutex>
#include <thread>

const size_t max_threads = 10;

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

  // Access data protected by the lock.
}

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

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

Compliant Solution

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

#include <mutex>
#include <thread>

const size_t max_threads = 10;

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

  // Access data protected by the lock.
}

std::mutex m;

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

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

Compliant Solution

This compliant solution eliminates the race condition by joining the threads before the mutex's destructor is invoked:

#include <mutex>
#include <thread>

const size_t max_threads = 10;

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

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

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

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

Risk Assessment

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

 

   
    

Related Vulnerabilities

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

Related Guidelines

MITRE CWECWE-667, Improper Locking

Bibliography

[ISO/IEC 14882-2014]Subclause 30.4, "Mutual exclusion"

 


  • No labels