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
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 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:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 |
Automated Detection
Tool | Version | Checker | Description |
---|---|---|---|
Astrée | 24.04 | pointer-qualifier-cast-const pointer-qualifier-cast-const-implicit | Fully checked |
Axivion Bauhaus Suite | 7.2.0 | CertC-EXP05 | Fully implemented |
CodeSonar | 8.1p0 | LANG.CAST.PC.CRCQ | Cast removes const qualifier |
Compass/ROSE | |||
1.2 | CC2.EXP05 | Fully implemented | |
GCC | 4.3.5 | Can detect violations of this recommendation when the | |
Helix QAC | 2024.3 | C0311, C0431 | |
LDRA tool suite | 9.7.1 | 203 S | Fully implemented |
Parasoft C/C++test | 2023.1 | 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 | 1.4 | 9005 | Partially supported |
Polyspace Bug Finder | R2024a | Checks for cast to pointer that removes const qualification (rec. fully supported) | |
RuleChecker | 24.04 | pointer-qualifier-cast-const pointer-qualifier-cast-const-implicit | Fully checked |
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
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" |
11 Comments
Stephen Friedl
This is a far harder problem to remediate than is suggested here: all of us will agree that you should not modify data that is *actually* constant, but it's so common to deal with library code written by others that doesn't properly qualify its parameters (even though they are known not to modify the pointed-to data) that one cannot always fix this without diving into the libraries bigtime *or* casting away the const.
Example: I made a serious pass over the Net::SNMP libraries some years ago to properly const qualify parameters to dozens and dozens of functions, and even though the patches were accepted by the project, portable code can't assume everybody is always and forever using a modern version (though I suppose that *secure* code might demand more modern versions, though not for this reason).
One must be very aggressive about properly const-qualifying one's own code so as not to foist this nastiness on others.
Robert Seacord
We do assume C99 as described in Scope (complete with rationale).
The only indication we provide of how hard a problem is, is in the remediation cost. I've modified this from medium to hard based on your comment. Unfortunately, this reduces the priority of applying the recommendation (because it makes more sense to fix problems that are easier to fix, but which have the same severity and likelihood).
Douglas A. Gwyn
It's actually a semantic violation (undefined behavior) to attempt to modify an object declared with const qualification.
As to casting away const-ness in other contexts, usually it's a mistake, but not always. Because "const" just means "read-only", not "constant", it is sometimes useful to declare some struct members as (pointer to) const objects in order 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 will probably be necessary to strip off the const qualification in order to update those members.
Hallvard Furuseth
(Edit: Part of this comment is nonsense as David points out - I was confusing two of your rules. Leaving it all behind for reference, and overstriking some.)
The text says "Casting away the const qualification allows violation of rule EXP31-C. Do not modify constant values prohibiting the modification of constant values."
Not true. Consider:
char buf-10;-
const char *ptr = buf;
strcpy((char *)ptr, "abcd");
It is the buf array which is being modified, and buf is not a constant value.
This is legal in C. Whether you can modify an object depends on whether that
object is defined as const, not on whether some pointer to it has a const*.
This rule in practice contradicts DCL00-A "Declare immutable values using enum or const".
(Which I think is a bad rule anyway. I'll go there to go on about that a bit.)
I think the various rules about const need to be consolidated into a more careful
discussion about when to constify.
To const or not to const is a problem even when there is no library API you need to
stay compliant with.
You may e.g. have some data structure which is read-only to most of the program, but
is written by a the few functions that maintain it. It may make sense to declare parts
of it const, and cast away const in the maintainer funcions.
Also, consider how you would define a function like strchr(). It can take both a
it can take a char* or const char*. A user passing a const char* value should not
have to cast away const in the argument. A user passing a char* value should not
have to cast away const in the return value. Thus your function should do just
what strchr does - take a const * argument, and cast away const in it.
(argh, 2 edits to get the example right [even before David's reply] - I'm getting tired...)
David Svoboda
Your comment from DCL00-A is a precise interpration,
const
really means 'read-only in this scope'. It does not restrict you from modifying the data from some other scope, or from a non-const pointer.I'm not sure what your example code is trying to prove, since you are explicitly casting away const.
You would
const
static data only if the program never modifies it...if it is modified in one location only, it's not constant, now, is it?You can
const
function arguments, but that doesn't mean the arg's data can't change, it only means the function promises not to change the data via that arg. The data is still changeable via another arg, or an aliasesd pointer, and the const-ness goes away once the function's done. So the fact that strchr() takes a const char* doesn't mean you can only pass it const data, it only means strchr() promises not to modify it.Hallvard Furuseth
Right, that was confused. You are not getting it right either though. Const does not mean 'read-only in this scope' either:
A function argument like "const int *arg" is not a promise the function won't change *arg, aliasing or no aliasing. All it promises is that the compiler will be rude if the function tries to change *arg or *(variable derived from arg) without casting away const at some point. Well, there are some escapes the compiler need not catch, like *(int **)(void *)&arg or (int *)(intptr_t)arg, or copying the pointer with memcpy.
OTOH if an object is created as const, that means it's immutable - or rather, since the implementation need not enforce that, it means an attempt to modify it yields undefined behavior.
Martin Sebor
As Douglas A. Gwyn notes above, casting away a
const
qualification from a pointer isn't necessarily problematic in and of itself. It's modifying an object declaredconst
after the cast that may lead to undefined behavior. Thus, in addition to this recommendation I suggest that there ought to be a rule prohibiting the modification of const objects, analogous to EXP32-C. Do not access a volatile object through a non-volatile reference:Do not modify a const object through a non-const reference
Both of the non-compliant examples on this page are actually violations of this (yet to be created) rule.
Robert Seacord (Manager)
Sounds OK to me. I thought what Doug was saying was that there was another valid exception to this guideline (which I added as an exception to this guideline).
Do you want to create the new rule or do you want me to? Looks like copy/paste this one and then make some modifications.
Don't the NCE/CS pairs here also violate this recommendation, or do you think this should only apply to explicit casts?
You may be able to shorten the title to "Do not modify a const object". How it is done is irrelevant, right?
You may also be able to cannibalize this rule EXP40-C. Do not modify constant values that ended up in the void.
Martin Sebor
Yes, the examples here apply to both this guideline and the one I'm proposing to add.
I'd be happy to add a new rule or resuscitate EXP40-C. Do not modify constant values. If I understand correctly, the main objection to that rule was the example(s) which demonstrated a violation of EXP05-C. Do not cast away a const qualification rather than the actual modification of constant objects.
After re-reading the examples in the rule I realize that the non-compliant example does, in fact, modify a const object and the objections were actually based on a particular compiler not diagnosing such modification and generating code that ran without suffering any adverse consequences of the undefined behavior. I don't think such objections are grounds for a dismissal of an otherwise valid rule. Compilers are free to provide well-defined semantics in cases where the standard leaves the behavior undefined. Unless the compiler documents this behavior, it is still undefined and may change as a result of compiler options. In addition, other compilers (on the same or other operating systems or hardware architectures) may generate code that will exhibit undefined behavior.
Robert Seacord (Manager)
I actually wrote that rule and never quite understood the objections to it, although alot of folks did seem to find some fault.
The non-compliant code example is right out of C99. I was surprised when I compiled it with whatever version of MSVS I had on my desktop and it compiled straight away w/o warning and successfully modified the constant. I reported this as a defect to Microsoft to diagnose the problem so newer versions of MSVS should work fine.
Long story short, I think perhaps you can revive it.
Martin Sebor
Done: EXP40-C. Do not modify constant values is back.