It is possible to reference 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 value but the resulting behavior lvalue is undefined . According to C99 Section behavior. The C Standard, 6.7.3 Type qualifiers Paragraph 5: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.
This also applies to objects that behave as if they were defined with qualified types such as an object at a memory-mapped input/output address.
Non-Compliant Code Example
This non-compliant code example allows a constant value to be modified.
Code Block |
---|
volatile char **cpp;
char *cp;
volatile char c = 'A';
cpp = &cp; // constraint violation
*cpp = &c; // valid
*cp = 'B'; // valid
|
The first assignment is unsafe because it would allow the following valid code to attempt to reference the
value of the volatile object c
.
Implementation Specific Details
If cpp
, cp
, and c
are declared as automatic (stack) variables, this example compiles without warning on Microsoft Visual C++ .NET (2003) and on MS Visual Studio 2005. In both cases, the resulting program changes the value of c
. Version 3.2.2 of the gcc compiler generates a warning but compiles. The resulting program changes the value of c
.
If cpp
, cp
, and c
are declared with static storage duration this program terminates abnormally in both cases.
Compliant Solution
The compliant solution depends on the intention of the programmer. If the intention is that the value of c
is modifiable, than it should not be declared as a constant. If the intention is that the value of c
is not meant to change, then do not write non-compliant code that attempts to modify it.
Priority: P2 Level: L3
Integer truncation errors can lead to buffer overflows and the execution of arbitrary code by an attacker.
Component | Value |
---|---|
Severity | 1 (low) |
Likelihood | 1 (unlikely) |
Remediation cost | 2 (medium) |
References
...
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; /* May produce a warning diagnostic */
ipp = (int**) &ip; /* Constraint violation; may produce a warning diagnostic */
*ipp = &i; /* Valid */
if (*ip != 0) { /* Valid */
/* ... */
}
} |
The assignment ipp = &ip
is not safe because it 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 *ip != 0
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++ mode (/TP
).
GCC 4.8.1 generates a warning but compiles successfully.
Compliant Solution
In this compliant solution, ip
is declared 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
Accessing an object with a volatile-qualified type through a reference with a non-volatile-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 | 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.
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" |
...