
Do not cast away a const
qualification on a variable an object of pointer type. Casting away the const
qualification allows a program to modify a constant valuethe object referred to by the pointer, which results may result in undefined behavior. See undefined behavior 61 in Appendix J of the C Standard.
As an illustration, C99 the C Standard [ISO/IEC 9899:2011] provides a footnote (subclause 6.7.3, paragraph 4):
The implementation may place a
const
object that is not volatile in a read-only region of storage. Moreover, the implementation need not allocate storage for such an object if its address is never used.
...
Noncompliant Code Example
The remove_spaces()
function in this non-compliant noncompliant code example accepts a pointer to a string str
and a string length slen
and removes the space character from the string by shifting the remaining characters towards toward the front of the string. The function remove_spaces()
is passed a const
char
pointer as an argument. The const
qualification is cast away, and then the contents of the string are modified.
Code Block | ||||
---|---|---|---|---|
| ||||
void remove_spaces(const char const *str, size_t slen) { char *p = (char *)str; size_t i; for (i = 0; i < slen && str[i]; i++) { if (str[i] != ' ') *p++ = str[i]; } *p = '\0'; } |
Compliant Solution
In this compliant solution, the function remove_spaces()
is passed a non-const
char
pointer. The calling function must ensure that the null-terminated byte string passed to the function is not const
by making a copy of the string or by other means.
Code Block | ||||
---|---|---|---|---|
| ||||
void remove_spaces(char *str, size_t slen) {
char *p = str;
size_t i;
for (i = 0; i < slen && str[i]; i++) {
if (str[i] != ' ') *p++ = str[i];
}
*p = '\0';
}
|
...
Noncompliant Code Example
In this non-compliant noncompliant code example, the contents of the const
int
array vals
are cleared by the call to memset()
.:
Code Block | ||||
---|---|---|---|---|
| ||||
const int vals[3] = {3, 4, 5};
memset(vals, 0, sizeof(vals));
|
Because the memset()
function takes a (non-const
) pointer to void
, the compiler must implicitly cast away const
.
Implementation Details
The GCC compiler GCC issues a warning when an implicit cast is performed.
Compliant Solution
If the intention is to allow the array values to be modified, do not declare the array as const
.:
Code Block | ||||
---|---|---|---|---|
| ||||
int vals[3] = {3, 4, 5};
memset(vals, 0, sizeof(vals));
|
Otherwise, do not attempt to modify the contents of the array.
Exceptions
EXP05-C-EX1: An exception to this rule recommendation is allowed when it is necessary to cast away const
when invoking a legacy API that does not accept a const
argument, provided the function does not attempt to modify the referenced variable. For example, the following code casts away the const
qualification of INVFNAME
in the call to the audit_log()
function.
Code Block |
---|
/* Legacy function defined elsewhere -elsewhere—cannot cannot be modified */ void audit_log(char *errstr) { fprintf(stderr, "Error: %s.\n", errstr); } /* ... */ const char const INVFNAME[] = "Invalid file name."; audit_log((char *)INVFNAME); /* EXP05-EX1 */ /* ... */ |
Automated Checking
The tool Compass / ROSE should be able to detect explicit casting away of a const object. So it should catch the first NCCE, which does just this.
ROSE should also be able to detect implicit casting away of a const pointer to memset()
, and to any other functions that take pointer arguments. To do this, it simply takes any function that is accepting a const pointer as argument, and view the function declaration (which will be available in the AST). So ROSE should be able to catch any const-casts, explicit or implicit.
ROSE won't be able to identify 'legitimate' const casts as specified in EXP05:EX1.
EXP05-C-EX2: A number of C standard library functions are specified to return non-const
pointers that refer to their const
-qualified arguments. When the actual arguments to such functions reference const
objects, attempting to use the returned non-const
pointers to modify the const
objects would be a violation of EXP40-C. Do not modify constant objects and would lead to undefined behavior. These functions are the following:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
For instance, in following example, the function strchr
returns an unqualified char*
that points to the terminating null character of the constant character array s
(which could be stored in ROM). Even though the pointer is not const
, attempting to modify the character it points to would lead to undefined behavior.
Code Block |
---|
extern const char s[];
char* where;
where = strchr(s, '\0');
/* Modifying *s is undefined */
|
Similarly, in the following example, the function strtol
sets the unqualified char*
pointer referenced by end
to point just past the last successfully parsed character of the constant character array s
(which could be stored in ROM). Even though the pointer is not const
, attempting to modify the character it points to would lead to undefined behavior.
Code Block |
---|
extern const char s[];
long x;
char* end;
x = strtol(s, &end, 0);
/* Modifying **end is undefined */
|
EXP05-C-EX3: Because const
means "read-only," and not "constant," it is sometimes useful to declare struct
members as (pointer to) const
objects to obtain diagnostics when the user tries to change them in some way other than via the functions that are specifically designed to maintain that data type. Within those functions, however, it may be necessary to strip off the const
qualification to update those membersIn C++, there is a const_cast
keyword specifically representing the casting away of const. My feeling would be that Rose should report const casts using the old syntax, but remain quiet on casts using the const_cast
keyword. This is mainly because const_cast
is explicitly meant to violate this rule and is easy to search for, while C-style casts may or may not violate this rule, and in general are very difficult to spot.
Risk Assessment
If the object is constant, the compiler may allocate storage in ROM or write-protected memory. Attempting to modify such an object may lead to a program crash or denial-of-service attack.
Recommendation | Severity | Likelihood | Detectable |
---|
Repairable | Priority | Level |
---|---|---|
EXP05- |
C | Medium |
Probable |
No |
No |
P4 |
L3 |
Automated Detection
...
Tool | Version | Checker | Description | ||||||
---|---|---|---|---|---|---|---|---|---|
Astrée |
| pointer-qualifier-cast-const pointer-qualifier-cast-const-implicit | Fully checked | ||||||
Axivion Bauhaus Suite |
| CertC-EXP05 | Fully implemented | ||||||
CodeSonar |
| LANG.CAST.PC.CRCQ | Cast removes const qualifier | ||||||
Compass/ROSE | |||||||||
| CC2.EXP05 | Fully implemented | |||||||
GCC |
| Can detect violations of this recommendation when the | |||||||
Helix QAC |
| C0311, C0431 | |||||||
LDRA tool suite |
| 203 S | Fully implemented | ||||||
Parasoft C/C++test |
| CERT_C-EXP05-a | A cast shall not remove any 'const' or 'volatile' qualification from the type of a pointer or reference | ||||||
PC-lint Plus |
| 9005 | Partially supported | ||||||
Polyspace Bug Finder |
| Checks for cast to pointer that removes const qualification (rec. fully supported) | |||||||
RuleChecker |
| pointer-qualifier-cast-const pointer-qualifier-cast-const-implicit | Fully checked |
The LDRA tool suite V 7.6.0 is able to detect violations of this recommendation.
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
References
...
Related Guidelines
SEI CERT C++ Coding Standard | EXP55-CPP. Do not access a cv-qualified object through a cv-unqualified type |
ISO/IEC TR 24772:2013 | Pointer Casting and Pointer Type Changes [HFC] Type System [IHN] |
MISRA C:2012 | Rule 11.8 (required) |
MITRE CWE | CWE-704, Incorrect type conversion or cast |
Bibliography
[ISO/IEC 9899:2011] | Subclause |
...
6.7.3, "Type Qualifiers" |
...
"Type qualifiers" \[[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.5EXP04-A. Do not perform byte-by-byte comparisons between structures 03. Expressions (EXP) EXP06-A. Operands to the sizeof operator should not contain side effects