An object that has volatile-qualified type may be modified in ways unknown to the implementation or have other unknown side effects. Referencing a volatile object by using a non-volatile lvalue is undefined behavior. The C Standard, 6.7.4 paragraph 7 [ISO/IEC 9899:2024], states
If an attempt is made to refer to an object defined with a volatile-qualified type through use of an lvalue with non-volatile-qualified type, the behavior is undefined.
See undefined behavior 65Do not cast away a volatile qualification on a variable type. Casting away the volatile qualification permits the compiler to optimize away operations on the volatile type, consequently negating the use of the volatile keyword in the first place.
Noncompliant Code Example
In this noncompliant code example, a volatile object is accessed through a non-volatile-qualified reference, resulting in undefined behavior.:
Code Block | ||||
---|---|---|---|---|
| ||||
#include <stdio.h> void func(void) { static volatile int **ipp; static int *ip; static volatile int i = 0; printf("i = %d.\n", i); ipp = &ip; /* producesMay warningsproduce ina modernwarning compilersdiagnostic */ ipp = (int**) &ip; /* constraintConstraint violation; may produce a warning diagnostic */ *ipp = &i; /* validValid */ if (*ip != 0) { /* validValid */ /* ... */ } } |
The assignment ipp = &ip
is unsafe not safe because it would allow allows the valid code that follows to reference the value of the volatile object i
through the non-volatile-qualified reference ip
. In this example, the compiler may optimize out the entire if
block because it is not possible that i *ip != 0
if i
must be false if the object to which ip
points is not volatile.
Implementation Details
This example compiles without warning on Microsoft Visual Studio 2013 when compiled in C mode (/TC
) but causes errors when compiled in C++ .NET mode (2003) and on MS Visual Studio 2005.
This example does not compile on MS Visual Studio 2008. The error message is
Code Block |
---|
error C2440: '=' : cannot convert from 'int **' to 'volatile int **'
|
/TP
).
GCC 4.8.1 generates a warning but compiles Version 3.2.2 and Version 4.1.3 of the GCC compiler generate a warning but compile successfully.
Compliant Solution
In this compliant solution, ip
is declared as volatile
.:
Code Block | ||||
---|---|---|---|---|
| ||||
#include <stdio.h> void func(void) { static volatile int **ipp; static volatile int *ip; static volatile int i = 0; printf("i = %d.\n", i); ipp = &ip; *ipp = &i; if (*ip != 0) { /* ... */ } } |
Risk Assessment
Casting away volatile allows access to Accessing an object with a volatile-qualified type through a reference with a non-volatile reference. This can result in undefined and perhaps unintended program -qualified type is undefined behavior.
Rule | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
EXP32-C |
Low |
Likely |
Medium | P6 | L2 |
Automated Detection
Tool | Version | Checker | Description | |||||
---|---|---|---|---|---|---|---|---|
Astrée |
| pointer-qualifier-cast-volatile |
...
pointer-qualifier-cast-volatile-implicit | Supported indirectly via MISRA C 2012 Rule 11.8 | ||||||||
Axivion Bauhaus Suite |
| CertC-EXP32 | Fully implemented | ||||||
Clang |
| -Wincompatible-pointer-types-discards-qualifiers | |||||||
Compass/ROSE | |||||||||
Coverity |
| MISRA C 2012 Rule 11.8 | Implemented | ||||||
Cppcheck Premium |
| premium-cert-exp32-c | Partially implemented | ||||||
GCC |
| Can detect violations of this rule when the | |||||||
Helix QAC |
| C0312, C0562, C0563, C0673, C0674 | Fully implemented | ||||||
Klocwork |
| CERT.EXPR.VOLATILE.ADDR |
...
PARAM | Fully implemented | ||||||||
LDRA tool suite |
| 344 S | Partially implemented | ||||||
Parasoft C/C++test |
| CERT_C-EXP32-a | A cast shall not remove any 'const' or 'volatile' qualification from the type of a pointer or reference | ||||||
Polyspace Bug Finder |
| Checks for cast to pointer that removes const or volatile qualification (rule fully covered) | |||||||
RuleChecker |
| pointer-qualifier-cast-volatile pointer-qualifier-cast-volatile-implicit | Supported indirectly via MISRA C 2012 Rule 11.8 |
...
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 EXP32-CPP. Do not cast away a volatile qualification.
References
Wiki Markup |
---|
\[[ISO/IEC 9899:1999|AA. C References#ISO/IEC 9899-1999]\] Section 6.7.3, "Type qualifiers," and Section 6.5.16.1, "Simple assignment"
\[[ISO/IEC PDTR 24772|AA. C References#ISO/IEC PDTR 24772]\] "HFC Pointer casting and pointer type changes" and "IHN Type system"
\[[MISRA 04|AA. C References#MISRA 04]\] Rule 11.5
\[[MITRE 07|AA. C References#MITRE 07]\] [CWE ID 704|http://cwe.mitre.org/data/definitions/704.html], "Incorrect Type Conversion or Cast" |
Related Guidelines
Key here (explains table format and definitions)
Taxonomy | Taxonomy item | Relationship |
---|---|---|
ISO/IEC TR 24772:2013 | Pointer Casting and Pointer Type Changes [HFC] | Prior to 2018-01-12: CERT: Unspecified Relationship |
ISO/IEC TR 24772:2013 | Type System [IHN] | Prior to 2018-01-12: CERT: Unspecified Relationship |
MISRA C:2012 | Rule 11.8 (required) | Prior to 2018-01-12: CERT: Unspecified Relationship |
CERT C | EXP55-CPP. Do not access a cv-qualified object through a cv-unqualified type | Prior to 2018-01-12: CERT: Unspecified Relationship |
Bibliography
[ISO/IEC 9899:2024] | 6.7.4, "Type Qualifiers" |
...
EXP31-C. Avoid side effects in assertions 03. Expressions (EXP) EXP33-C. Do not reference uninitialized memory