CertC-EXP05¶
Do not cast away a const qualification
Required inputs: IR
Do not cast away a
const qualification on an object of pointer type. Casting away the
const qualification allows a program to modify the object referred
to by the pointer, which may result in
undefined
behavior. See
undefined
behavior 64 in Appendix J of the C Standard.
As an illustration, the C Standard [ ISO/IEC 9899:2011] provides a footnote (subclause 6.7.3, paragraph 4):
The implementation may place a
constobject 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 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 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.
void remove_spaces(const char *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.
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 noncompliant code example, the contents of the
const
int array
vals are cleared by the call to
memset():
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 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:
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 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.
/* Legacy function defined elsewhere-cannot be modified */
void audit_log(char *errstr) {
fprintf(stderr, "Error: %s.\n", errstr);
}
/* ... */
const char INVFNAME[] = "Invalid file name.";
audit_log((char *)INVFNAME); /* 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:
memchr |
strchr |
strpbrk |
strrchr |
strstr |
strtod |
strtof |
strtold |
strtol |
strtoll |
strtoul |
strtoull |
wmemchr |
wcschr |
wcspbrk |
wcsrchr |
wcsstr |
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.
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.
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 members.
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 | Remediation Cost | Priority | Level |
|---|---|---|---|---|---|
| EXP05-C | Medium | Probable | Medium | P8 | L2 |
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" |
Possible Messages
Key |
Text |
Severity |
Disabled |
|---|---|---|---|
cast_removes_atomic |
Cast removes _Atomic qualification |
None |
False |
cast_removes_const |
Cast removes const qualification |
None |
False |
cast_removes_volatile |
Cast removes volatile qualification |
None |
False |
implicit_cast_removes_atomic |
Implicit cast removes _Atomic qualification |
None |
False |
implicit_cast_removes_const |
Implicit cast removes const qualification |
None |
False |
implicit_cast_removes_volatile |
Implicit cast removes volatile qualification |
None |
False |
Options¶
This rule shares the following common options: exclude_in_macros, exclude_messages_in_system_headers, excludes, extend_exclude_to_macro_invocations, includes, justification_checker, languages, post_processing, provider, report_at, severity
The following places define options that affect this rule: Stylechecks, Analysis-GlobalOptions
check_atomic¶
check_atomic : bool = False
check_const¶
check_const : bool = True
check_volatile¶
check_volatile : bool = False
only_top_level¶
only_top_level : bool = False