Versions Compared

Key

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

...

This property of the volatile keyword is sometimes confused as providing atomicity of a variable that is shared between threads in a multithreaded program. A variable declared as volatile is not cached in a register, leading to this confusion that it can be used safely as a synchronization primitive. When declared volatile, the compiler does not re-order the sequence of reads and writes to that memory location. However, the compiler might re-order these reads and writes with those to other memory locations. This might result in non-atomic operations on the synchronization variable resulting in errors.

Noncompliant Code Example

This noncompliant code example uses flag as a synchronization primitive.

Code Block
bgColor#ffcccc
langc

bool flag = false;

void test() {
  while (!flag) {
    sleep(1000);
  }
}

void wakeup(){
  flag = true;
}

void debit(unsigned int amount){
  test();
  account_balance -= amount;
}

In this example, the value of flag is used to determine if the critical section can be executed or not. Because the flag variable is not declared volatile, it may be cached in registers. Before the value in the register is written to memory, another thread might be scheduled to run, resulting in that thread reading stale data.

Noncompliant Code Example

This noncompliant code example uses flag as a synchronization primitive but qualifies flag as a volatile type.

Code Block
bgColor#ffcccc
langc

volatile bool flag = false;

void test() {
  while (!flag){
    sleep(1000);
  }
}

void wakeup(){
  flag = true;
}

void debit(unsigned int amount) {
  test();
  account_balance -= amount;
}

Declaring flag volatile solves the problem of reading stale data, but still does not provide atomicity guarantees needed for synchronization primitives to work correctly. The volatile keyword does not promise to provide the guarantees needed for synchronization primitives.

Compliant Solution

This code uses a mutex to protect critical sections.

Code Block
bgColor#ccccff
langc

#include <pthread<threads.h>

int account_balance;
pthread_mutexmtx_t flag;

/* Initialize = PTHREAD_MUTEX_INITIALIZER;flag */

void debit(unsigned int amount) {
  pthreadmtx_mutex_lock(&flag);
  account_balance -= amount; /* Inside critical section */
  pthread_mutexmtx_unlock(&flag);
}

Risk Assessment

Recommendation

Severity

Likelihood

Remediation Cost

Priority

Level

POS03CON02-C

Medium

Probable

Medium

P8

L2

Related Guidelines

CERT C++ Secure Coding Standard: CON01-CPP. Do not use volatile as a synchronization primitive

ISO/IEC 9899:1999 Section 5.1.2.3 "Program Execution"

Bibliography

Open Group 2004] Section 4.11 "Memory Synchronization"

...