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

Compare with Current View Page History

« Previous Version 52 Next »

An object that has volatile-qualified type may be modified in ways unknown to the implementation or have other unknown side effects. Asynchronous signal handling falls into this category. Without this type qualifier, unintended optimizations may occur.

The volatile keyword eliminates this confusion by imposing restrictions on access and caching. According to the C99 Rationale [[ISO/IEC 03]]:

No cacheing through this lvalue: each operation in the abstract semantics must be performed (that is, no cacheing assumptions may be made, since the location is not guaranteed to contain any previous value). In the absence of this qualifier, the contents of the designated location may be assumed to be unchanged except for possible aliasing.

Please keep in mind that while adding volatile will ensure that a compiler does not perform unintended reordering or optimization, it in no way guarantees synchronization between multiple threads nor does it otherwise ward against simultaneous memory accesses.

Noncompliant Code Example

This noncompliant code example relies on the reception of a SIGINT signal to toggle a flag to terminate a loop.

#include <signal.h>

sig_atomic_t i;

void handler(int signum) {
  i = 0;
}

int main(void) {
  i = 1;
  signal(SIGINT, handler);
  while (i) {
   /* do something */
  }
  return 0;
}

However, if the value of i is cached, the while loop may never terminate. When compiled on GCC with the -O optimization flag, for example, the program fails to terminate even upon receiving a SIGINT.

Noncompliant Code Example

This noncompliant code example prevents the compiler from optimizing away the loop condition, by type casting the variable to volatile within the while loop.

#include <signal.h>

sig_atomic_t i;

void handler(int signum) {
  i = 0;
}

int main(void) {
  i = 1;
  signal(SIGINT, handler);
  while (*(volatile sig_atomic_t *)&i) {
   /* do something */
  }
  return 0;
}

Such a solution may be necessary to prevent the compiler from optimizing away the memory lookup while allowing for caching and optimizations elsewhere in the code.

However, this solution violates SIG31-C. Do not access or modify shared objects in signal handlers.

Compliant Solution

By adding the volatile qualifier to the variable declaration, i is guaranteed to be accessed from its original address for every iteration of the while loop as well as from within the signal handler.

#include <signal.h>

volatile sig_atomic_t i;

void handler(int signum) {
  i = 0;
}

int main(void) {
  i = 1;
  signal(SIGINT, handler);
  while (i) {
   /* do something */
  }
  return 0;
}

The sig_atomic_t type is the integer type of an object that can be accessed as an atomic entity, even in the presence of asynchronous interrupts. The type of sig_atomic_t is implementation defined, though it has some guarantees. Integer values from 0 through 127 can be safely stored to a variable of type sig_atomic_t.

Risk Assessment

Failing to use the volatile qualifier can result in race conditions in asynchronous portions of the code, causing unexpected values to be stored and leading to possible data integrity violations.

Rule

Severity

Likelihood

Remediation Cost

Priority

Level

DCL34-C

low

probable

high

P2

L3

Related Vulnerabilities

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

Other Languages

This rule appears in the C++ Secure Coding Standard as DCL34-CPP. Use volatile for data that cannot be cached.

References

[[ISO/IEC 9899:1999]] Section 6.7.3, "Type qualifiers," and Section 7.14, "Signal handling <signal.h>"
[[ISO/IEC 03]] Section 6.7.3, "Type qualifiers"
[[Sun 05]] Chapter 6, "Transitioning to ISO C"


DCL33-C. Ensure that restrict-qualified source and destination pointers in function arguments do not reference overlapping objects      02. Declarations and Initialization (DCL)       DCL35-C. Do not invoke a function using a type that does not match the function definition

  • No labels