Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Parasoft C/C++test 10.4

The C Standard, subclause 5.1.2.3, paragraph 2 [ISO/IEC 9899:2011], says,

Accessing a volatile object, modifying an object, modifying a file, or calling a function that does any of those operations are all side effects, which are changes in the state of the execution environment. Evaluation of an expression in general includes both value computations and initiation of side effects. Value computation for an lvalue expression includes determining the identity of the designated object.

The volatile keyword informs the compiler that the qualified variable may change in ways that cannot be determined; consequently, compiler optimizations must be restricted for memory areas marked as volatile. For example, the compiler is forbidden to load the value into a register and subsequently reuse the loaded value rather than accessing memory directly. This concept relates to multithreading because incorrect caching of a shared variable may interfere with the propagation of modified values between threads, causing some threads to view stale data.

The volatile keyword is sometimes misunderstood to provide atomicity for variables that are volatile keyword is a hint to the compiler telling it not to optimize operations on that memory location, but instead perform memory accesses for reads and writes. 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 as volatile the compiler does not re-order Because the compiler is forbidden to either cache variables declared as volatile in registers or to reorder the sequence of reads and writes to any given volatile variable, many programmers mistakenly believe that volatile variables can correctly serve as synchronization primitives. Although the compiler is forbidden to reorder the sequence of reads and writes to that memory location. However, the compiler might re-order a particular volatile variable, it may legally reorder these reads and writes with those respect to reads and writes to other memory locations. This might result in non atomic operations on the synchronization variable resulting in errorsreordering alone is sufficient to make volatile variables unsuitable for use as synchronization primitives.

Further, the volatile qualifier lacks any guarantees regarding the following desired properties necessary for a multithreaded program:

  • Atomicity: Indivisible memory operations.
  • Visibility: The effects of a write action by a thread are visible to other threads.
  • Ordering: Sequences of memory operations by a thread are guaranteed to be seen in the same order by other threads.

The volatile qualifier lacks guarantees for any of these properties, both by definition and by the way it is implemented in various platforms. For more information on how volatile is implemented, consult DCL17-C. Beware of miscompiled volatile-qualified variables.

Noncompliant Code Example

The following code uses This noncompliant code example attempts to use 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 the above piece of codethis example, the value of flag is used to determine if whether the critical section can be executed or not. Because the flag variable is not declared as being of type volatile and so volatile, it may be cached in registers. Before the value in the register is written to memory, another thread might be scheduled to run and so may end up , resulting in that thread reading stale data.

Noncompliant Code Example

The following This noncompliant code example uses flag as a synchronization primitive but this time declared as type volatilequalifies 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 as volatile solves the problem of reading values being cached, which causes stale data , but still does not provide atomicity to be read. However, volatile flag still fails to provide the atomicity and visibility guarantees needed for synchronization primitives to work correctly. The volatile keyword does not promise to provide the guarantees needed for synchronization primitives.

Compliant

...

Solution

The compliant code example would involve using This code uses a mutex to protect critical sections.:

Code Block
bgColor#ccccff
langc
#include <pthread<threads.h>

volatile int account_balance;
pthread_mutexmtx_t flag;

/* Initialize = PTHREAD_MUTEX_INITIALIZER;flag */

voidint debit(unsigned int amount) {
  pthread_mutexif (mtx_lock(&flag) == thrd_error) {
    return -1;  /* Indicate error */
  }
 
 account account_balance -= amount; //* Inside critical section */

  if (mtx_unlock(&flag) == thrd_error) {
     pthread_mutex_unlockreturn -1;  /* Indicate error */
  }

  return 0;
}

Compliant Solution (Critical Section, Windows)

This compliant solution uses a Microsoft Windows critical section object to make operations involving account_balance atomic [MSDN].

Code Block
bgColor#ccccff
langc
#include <Windows.h>

static volatile LONG account_balance;
CRITICAL_SECTION flag;

/* Initialize flag */
InitializeCriticalSection(&flag);
 
int debit(unsigned int amount) {
  EnterCriticalSection(&flag); 
  account_balance -= amount; /* Inside critical section */
  LeaveCriticalSection(&flag);
 
  return 0;
}

Risk Assessment

Recommendation

Severity

Likelihood

Remediation Cost

Priority

Level

POS40

CON02-C

Medium

Probable

Medium

P12

L1

Other Languages

P8

L2

Automated Detection

ToolVersionCheckerDescription
Parasoft C/C++test
Include Page
Parasoft_V
Parasoft_V

CERT_C-CON02-a

Do not use the volatile keyword

Related Guidelines

Key here (explains table format and definitions)

Taxonomy

Taxonomy item

Relationship

CERT CCON01

...

-CPP. Do not use volatile as a synchronization primitivePrior to 2018-01-12: CERT: Unspecified Relationship

Bibliography

[IEEE Std 1003.1:2013]Section 4.11, "Memory Synchronization"
[ISO/IEC 9899:2011]Subclause 5.1.2.3, "Program Execution"
[MSDN]


...

Image Added Image Added Image Added