CERT.CONC.UNSAFE_COND_VAR

Preserve thread safety and liveness when using condition variables.

The wait() function must be invoked from a loop that checks whether a condition predicate holds. A condition predicate is an expression constructed from the variables of a function that must be true for a thread to be allowed to continue execution.

Vulernability and risk

If the call to wait() without in a condition predicate loop, it consequently fails to check the condition predicate after the notification is received. If the notification was spurious or malicious, the thread would wake up prematurely.

Mitigation and prevention

The wait() function must be invoked from a loop that checks whether a condition predicate holds.

Example

Copy
  #include <condition_variable>
  #include <mutex>
  
  struct Node {
    void *node;
    struct Node *next;
  };
  
  static Node list;
 static std::mutex m;
 static std::condition_variable condition;
 
 void consume_list_element1(std::condition_variable &condition) {
   std::unique_lock<std::mutex> lk(m);
 
   if (list.next == nullptr) {
     condition.wait(lk);          // Uncompliant code.
   }
 
   // Proceed when condition holds.
 }
 
 void consume_list_element2() {
   std::unique_lock<std::mutex> lk(m);
 
   while (list.next == nullptr) {
     condition.wait(lk);         // Compliant code
   }
 
   // Proceed when condition holds.
 }
 
 void consume_list_element3() {
   std::unique_lock<std::mutex> lk(m);
 
   condition.wait(lk, []{ return list.next; });       //Compliant code.
   // Proceed when condition holds.
 }