Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

This thread pauses execution using cnd_wait() and resumes when notified, presumably when the list has elements to be consumed. It is possible for the thread to be notified even if the list is still empty, perhaps because the notifying thread used cndnotify_broadcastall(), which notifies all threads. Notification using cndnotify_broadcastall() is frequently preferred over using cndnotify_signalone() (see CON38-C. Preserve thread safety and liveness when using condition variables for more information).

...

This noncompliant code example nests the cnd_call to wait() function inside  inside an if block and 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.

Code Block
bgColor#FFcccc
langc
#include <stddef.h><condition_variable>
#include <threads.h><mutex>
  
struct node_t {
  void *node;
  struct node_t *next;
};
  
struct node_t list;
static mtx_t lockstd::mutex m;
static cnd_tstd::condition_variable condition;
  
void consume_list_element(void) {
  if (thrd_success != mtx_lock(&lock)) {
    /* Handle error */
  }
 
  std::unique_lock<std::mutex> lk(m);
  
  if (list.next == NULL) {
    if (thrd_success != cnd_wait(&condition, &lock)) {
      /* Handle error */
    }
  }
condition.wait(lk);
  }
 
  /* Proceed when condition holds */

  if (thrd_success != mtx_unlock(&lock)) {
    /* Handle error */
  }
}

Compliant Solution

This compliant solution calls the cnd_wait() function  member function from within a while loop to check the condition both before and after the call to cnd_wait():

Code Block
bgColor#ccccff
langc
#include <stddef.h><condition_variable>
#include <threads.h><mutex>
  
struct node_t {
  void *node;
  struct node_t *next;
};
  
struct node_t list;
static mtx_t lockstd::mutex m;
static cnd_tstd::condition_variable condition;
  
void consume_list_element(void) {
  if (thrd_success != mtx_lock(&lock)) {
    /* Handle error */
  }
std::unique_lock<std::mutex> lk(m);
  
  while (list.next == NULL) {
    if (thrd_success != cnd_wait(&condition, &lock)) {
      /* Handle error */
  condition.wait(lk);
  }
  }

  /* Proceed when condition holds */

  if (thrd_success != mtx_unlock(&lock)) {
    /* Handle error */
  }
}

Risk Assessment

Failure to enclose calls to the cnd_wait() or cnd_timedwait() functions wait(), wait_for(), or wait_until() member functions inside a while loop can lead to indefinite blocking and denial of service (DoS).

...