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, for example, may cause objects to be modified in a manner unknown to the compiler. Without this type qualifier, unintended optimizations may occur. These optimizations may cause race conditions , because a programmer may write code that prevents a race condition, yet the compiler is not aware of the programmer's data model, and may modify the code during compilation to permit race conditions.
| Wiki Markup |
|---|
The {{volatile}} keyword eliminates this confusion by imposing restrictions on access and caching. According to the C99 Rationale \[[ISO/IEC 03|AA. Bibliography#ISO/IEC 03]\]: |
No caching through this lvalue: each operation in the abstract semantics must be performed (that is, no cacheing caching assumptions may be made, because 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.
While type qualifying objects as volatile ensures that a compiler does not perform unintended reordering or optimization, it in no way guarantees synchronization between multiple threads, ward protects against simultaneous memory accesses, and, unless used to declare objects of type sig_atomic_t guarantee , guarantees atomicity of accesses to the object. For restrictions specific to signal handlers, see guideline SIG31-C. Do not access or modify shared objects in signal handlers.
...
In this noncompliant code example, the function thread_func function runs in the context of multiple threads designed to communicate with one another via the global variable end_processing. The function attempts to prevent the compiler from optimizing away the while loop condition by casting the variable to volatile before accessing it. However, because end_processing is not declared volatile, the assignment to it in the body of the loop does not need not to be flushed from a register into memory and thus may not be visible when read despite the cast. As a result, the loop may never terminate.
Note, however, that declaring an object volatile is not sufficient to prevent data races when the object is simultaneously accessed from within two or more threads of execution. Additional memory visibility constraints may necessitate the use of platform-specific constructs such as memory barriers, for example, when each of the threads runs on a different processor.
...
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
Other Languages
Related Guidelines
This rule appears in the C++ Secure Coding Standard as : DCL34-CPP. Use volatile for data that cannot be cached.
Bibliography
| Wiki Markup |
|---|
\[[ISO/IEC 9899:1999|AA. Bibliography#ISO/IEC 9899-1999]\] Section 6.7.3, "Type qualifiers," and Section 7.14, "Signal handling <signal.h>" \[[ISO/IEC 032003|AA. Bibliography#ISO/IEC 03]\] Section 6.7.3, "Type qualifiers" \[[Sun 052005|AA. Bibliography#Sun 05]\] [Chapter 6, "Transitioning to ISO C"|http://docs.sun.com/source/819-3688/tguide.html#pgfId-997898] |
...