CertC-ENV30¶
Do not modify the object referenced by the return value of certain functions
Required inputs: IR
Some functions return a pointer to an object that cannot be modified without
causing
undefined
behavior. These functions include
getenv(),
setlocale(),
localeconv(),
asctime(), and
strerror(). In such cases, the function call results must be
treated as being
const-qualified.
The C Standard, 7.22.4.6, paragraph 4 [
ISO/IEC
9899:2011], defines
getenv() as follows:
The
getenvfunction returns a pointer to a string associated with the matched list member. The string pointed to shall not be modified by the program, but may be overwritten by a subsequent call to thegetenvfunction. If the specified name cannot be found, a null pointer is returned.
If the string returned by
getenv() must be altered, a local copy should be created. Altering
the string returned by
getenv() is
undefined
behavior. (See
undefined
behavior 184.)
Similarly, subclause 7.11.1.1, paragraph 8 [
ISO/IEC
9899:2011], defines
setlocale() as follows:
The pointer to string returned by the
setlocalefunction is such that a subsequent call with that string value and its associated category will restore that part of the program's locale. The string pointed to shall not be modified by the program, but may be overwritten by a subsequent call to thesetlocalefunction.
And subclause 7.11.2.1, paragraph 8 [
ISO/IEC
9899:2011], defines
localeconv() as follows:
The
localeconvfunction returns a pointer to the filled-in object. The structure pointed to by the return value shall not be modified by the program, but may be overwritten by a subsequent call to thelocaleconvfunction. In addition, calls to thesetlocalefunction with categoriesLC_ALL,LC_MONETARY, orLC_NUMERICmay overwrite the contents of the structure.
Altering the string returned by
setlocale() or the structure returned by
localeconv() are
undefined
behaviors. (See
undefined
behaviors 120 and
121.)
Furthermore, the C Standard imposes no requirements on the
contents of the string by
setlocale(). Consequently, no assumptions can be made as to the
string's internal contents or structure.
Finally, subclause 7.24.6.2, paragraph 4 [ ISO/IEC 9899:2011], states
The
strerrorfunction returns a pointer to the string, the contents of which are locale-specific. The array pointed to shall not be modified by the program, but may be overwritten by a subsequent call to thestrerrorfunction.
Altering the string returned by
strerror() is
undefined
behavior. (See
undefined
behavior 184.)
Noncompliant Code Example (
getenv())
This noncompliant code example modifies the string returned by
getenv() by replacing all double quotation marks (
") with underscores (
_):
#include <stdlib.h>
void trstr(char *c_str, char orig, char rep) {
while (*c_str != '\0') {
if (*c_str == orig) {
*c_str = rep;
}
++c_str;
}
}
void func(void) {
char *env = getenv("TEST_ENV");
if (env == NULL) {
/* Handle error */
}
trstr(env,'"', '_');
}
Compliant Solution (
getenv()) (Environment Not Modified)
If the programmer does not intend to modify the environment, this compliant solution demonstrates how to modify a copy of the return value:
#include <stdlib.h>
#include <string.h>
void trstr(char *c_str, char orig, char rep) {
while (*c_str != '\0') {
if (*c_str == orig) {
*c_str = rep;
}
++c_str;
}
}
void func(void) {
const char *env;
char *copy_of_env;
env = getenv("TEST_ENV");
if (env == NULL) {
/* Handle error */
}
copy_of_env = (char *)malloc(strlen(env) + 1);
if (copy_of_env == NULL) {
/* Handle error */
}
strcpy(copy_of_env, env);
trstr(copy_of_env,'"', '_');
/* ... */
free(copy_of_env);
}
Compliant Solution (
getenv()) (Modifying the Environment in POSIX)
If the programmer's intent is to modify the environment, this compliant
solution, which saves the altered string back into the environment by using the
POSIX
setenv() and
strdup() functions, can be used:
#include <stdlib.h>
#include <string.h>
void trstr(char *c_str, char orig, char rep) {
while (*c_str != '\0') {
if (*c_str == orig) {
*c_str = rep;
}
++c_str;
}
}
void func(void) {
const char *env;
char *copy_of_env;
env = getenv("TEST_ENV");
if (env == NULL) {
/* Handle error */
}
copy_of_env = strdup(env);
if (copy_of_env == NULL) {
/* Handle error */
}
trstr(copy_of_env,'"', '_');
if (setenv("TEST_ENV", copy_of_env, 1) != 0) {
/* Handle error */
}
/* ... */
free(copy_of_env);
}
Noncompliant Code Example (
localeconv())
In this noncompliant example, the object returned by
localeconv() is directly modified:
#include <locale.h>
void f2(void) {
struct lconv *conv = localeconv();
if ('\0' == conv->decimal_point[0]) {
conv->decimal_point = ".";
}
}
Compliant Solution (
localeconv()) (Copy)
This compliant solution modifies a copy of the object returned by
localeconv():
#include <locale.h>
#include <stdlib.h>
#include <string.h>
void f2(void) {
const struct lconv *conv = localeconv();
if (conv == NULL) {
/* Handle error */
}
struct lconv *copy_of_conv = (struct lconv *)malloc(
sizeof(struct lconv));
if (copy_of_conv == NULL) {
/* Handle error */
}
memcpy(copy_of_conv, conv, sizeof(struct lconv));
if ('\0' == copy_of_conv->decimal_point[0]) {
copy_of_conv->decimal_point = ".";
}
/* ... */
free(copy_of_conv);
}
Risk Assessment
Modifying the object pointed to by the return value of
getenv(),
setlocale(),
localeconv(),
asctime(), or
strerror() is
undefined
behavior. Even if the modification succeeds, the modified object can be
overwritten by a subsequent call to the same function.
| Rule | Severity | Likelihood | Remediation Cost | Priority | Level |
|---|---|---|---|---|---|
| ENV30-C | Low | Probable | Medium | P4 | L3 |
Related Guidelines
| Taxonomy | Taxonomy item | Relationship |
|---|---|---|
| ISO/IEC TS 17961:2013 | Modifying the string returned by
getenv,
localeconv,
setlocale, and
strerror [libmod]
|
Prior to 2018-01-12: CERT: Unspecified Relationship |
Bibliography
| [ IEEE Std 1003.1:2013] | XSH, System Interfaces,
getenvXSH, System Interfaces, setlocaleXSH, System Interfaces, localeconv
|
| [ ISO/IEC 9899:2011] | 7.11.1.1, "The
setlocale Function"7.11.2.1, "The localeconv Function"7.22.4.6, "The getenv Function"7.24.6.2, "The strerror Function"
|
Possible Messages
Key |
Text |
Severity |
Disabled |
|---|---|---|---|
nonconst_system_pointer_retrievals |
Return value should be assigned to a pointer to const-qualified type. |
None |
False |
string_of_system_pointer_modified |
Return value of call to system function should be considered const, including strings referenced by it |
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
funcs¶
funcs : set[bauhaus.analysis.config.QualifiedName] = {'asctime', 'getenv', 'localeconv', 'setlocale', 'strerror'}