As described in - depth in guideline [DCL34in rule DCL22-C. Use volatile for data that cannot be cached], a {{ Wiki Markup volatile
}}\-qualified variable "shall be evaluated strictly according to the rules of the abstract machine" \ [[ISO/IEC 9899:1999|AA. Bibliography#ISO/IEC 9899-1999]\]. In other words, the {{volatile}} qualifier is used to instruct the compiler to not make caching optimizations about a variable.
Wiki Markup |
---|
However, as demonstrated in \[[Eide and Regehr|AA. Bibliography#Eide and Regehr]\], all tested compilers generated some percentage of incorrect compiled code with regards to {{volatile}} accesses. Therefore, it is necessary to know how your compiler behaves when the standard {{volatile}} behavior is required. There is also a workaround that eliminates some or all of these errors \[[Eide and Regehr|AA. Bibliography#Eide and Regehr]\]. |
Noncompliant Code Example
2011]. In other words, the volatile
qualifier is used to instruct the compiler to not make caching optimizations about a variable.
However, as demonstrated in "Volatiles Are Miscompiled, and What to Do about It" [Eide and Regehr], all tested compilers generated some percentage of incorrect compiled code with regard to volatile
accesses. Therefore, it is necessary to know how your compiler behaves when the standard volatile
behavior is required. The authors also provide a workaround that eliminates some or all of these errors.
Noncompliant Code Example
As demonstrated in Eide and Regehr's work, the following code example compiles incorrectly using GCC 4.3.0 for IA32 and the -Os
optimization As demonstrated in \[[Eide and Regehr|AA. Bibliography#Eide and Regehr]\], the following code example compiles incorrectly using GCC version 4.3.0 for IA32 and the {{\-Os}} optimization flag: Wiki Markup
Code Block | ||||
---|---|---|---|---|
| ||||
const volatile int x; volatile int y; void foo(void) { for(y = 0; y < 10; y++) { int z = x; } } |
...
Because the variable {{x
}} is {{volatile
}}\-qualified, it should be accessed ten accessed 10 times in this program. However, as shown in the compiled object code, it is accessed only accessed once due to a loop-hoisting optimization \ [[Eide and Regehr|AA. Bibliography#Eide and Regehr]\]:
Code Block | ||||
---|---|---|---|---|
| ||||
foo:
movl $0, y
movl x, %eax
jmp .L2
.L3:
movl y, %eax
incl %eax
movl %eax, y
.L2:
movl y, %eax
cmpl $10, %eax
jg .L3
ret
|
Should x
represent a hardware register or some other memory-mapped device that has side effects when accessed, the previous miscompiled code example may produce unexpected behavior.
Compliant Solution
Eide and Regehr tested a workaround by wrapping {{ Wiki Markup volatile
}} accesses with function calls. They describe it with the intuition that "we can replace an action that compilers empirically get wrong by a different actionâa function callâthat compilers can get right" \[[Eide and Regehr|AA. Bibliography#Eide and Regehr]\]. For example, the workaround for the noncompliant code example would action—a function call—that compilers can get right" [Eide and Regehr]. For example, the workaround for the noncompliant code example would be
Code Block | ||||
---|---|---|---|---|
| ||||
int vol_read_int(volatile int *vp) {
return *vp;
}
volatile int *vol_id_int(volatile int *vp) {
return vp;
}
const volatile int x;
volatile int y;
void foo(void) {
for(*vol_id_int(&y) = 0; vol_read_int(&y) < 10; *vol_id_int(&y) = vol_read_int(&y) + 1) {
int z = vol_read_int(&x);
}
}
|
...
The workarounds proposed in \[[Eide and Regehr|AA. Bibliography#Eide and Regehr]\] fix many of the {{volatile}}\-access bugs in the tested compilers. However, compilers are always changing so critical sections of code should be compiled as if for deployment and the compiled object code should be inspected for the correct behavior.
...
proposed by Eide and Regehr fix many of the volatile
-access bugs in the tested compilers. However, compilers are always changing, so critical sections of code should be compiled as if for deployment, and the compiled object code should be inspected for the correct behavior.
Risk Assessment
The volatile
qualifier should be used with caution in mission-critical situations. Always make sure that code that assumes certain behavior when using the volatile
qualifier is inspected at the object code level for compiler bugs.
Rule | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
DCL17-C | medium Medium | probable Probable | high High | P4 | L3 |
Bibliography
...
Automated Detection
Tool | Version | Checker | Description | ||||||
---|---|---|---|---|---|---|---|---|---|
LDRA tool suite |
| 134 S | Partially implemented |
Bibliography
[Eide and Regehr] | "Volatiles Are Miscompiled, and What to Do about It" |
[ISO/IEC 9899:2011] | Subclause 6.7.3, |
...
"Type Qualifiers" |
...
qualifiers"DCL16-C. Use 'L', not 'l', to indicate a long value 02. Declarations and Initialization (DCL)