Some functions return a pointer to an object that cannot be modified without causing undefined behavior. These functions include the standard getenv()
, setlocale()
, localeconv()
, and strerror()
functions.
Section Subclause 7.22.4.6 of the C Standard [ISO/IEC 9899:2011] defines getenv
as follows:
...
Consequently, if the string returned by getenv()
must be altered, a local copy should be created. Altering the string returned by getenv()
results in undefined behavior. See also undefined behavior 184 of Annex J of the C Standard.
Similarly, Section subclause 7.11.1.1 [ISO/IEC 9899:2011] defines setlocale
and localeconv
as follows:
...
Altering the string returned by setlocale()
or the structure returned by localeconv()
results in undefined behavior. See also undefined behaviors 120 and 121 of Annex J. Furthermore, the C Standard imposes no requirements on the contents of the string by setlocale()
. Consequently, a program should make no assumptions as to the string's internal contents or structure.
Finally, Section subclause 7.24.6.2 [ISO/IEC 9899:2011], states:
...
Code Block | ||||
---|---|---|---|---|
| ||||
#include <stdlib.h> void trstr(char *str, char orig, char rep) { while (*str != '\0') { if (*str == orig) { *str = rep; } str++; } } /* ... */ void func(void) { char *env = getenv("TEST_ENV"); if (env == NULL) { /* Handle error */ } trstr(env,'"', '_'); /* ... */} |
Compliant Solution (getenv()
) (Local Copy)
...
Code Block | ||||
---|---|---|---|---|
| ||||
#include <stdlib.h> #include <string.h> void trstr(char *str, char orig, char rep) { while (*str != '\0') { if (*str == orig) { *str = rep; } 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,'\"', '_'); } |
Compliant Solution (getenv()
) (Modifying the Environment in POSIX)
...
Code Block | ||||
---|---|---|---|---|
| ||||
#include <stdlib.h> #include <string.h> void trstr(char *str, char orig, char rep) { while (*str != '\0') { if (*str == orig) { *str = rep; } 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 */ } } |
Noncompliant Code Example (localeconv()
)
...
Code Block | ||||
---|---|---|---|---|
| ||||
#include <locale.h> void f2(void) { struct lconv *conv = localeconv(); if ('\0' == conv->decimal_point[0]) { conv->decimal_point = "."; /* violation */ } if ('\0' == conv->thousands_sep[0]) { conv->thousands_sep = ","; /* violation */ } /* ... */ } |
Compliant Solution (localeconv()
) (Local Copy)
...
Code Block | ||||
---|---|---|---|---|
| ||||
#include <locale.h> #include <stdlib.h> #include <string.h> void f2(void) { struct lconv *conv = localeconv(); struct lconv *copy_of_conv; if (conv == NULL) { /* Handle error */ } copy_of_conv = (charstruct lconv*)malloc(sizeof(struct lconv) + 1); 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 = "."; } if ('\0' == copy_of_conv->thousands_sep[0]) { copy_of_conv->thousands_sep = ","; } /* ... */ } |
Risk Assessment
Depending on the implementation, modifying the object pointed to by the return value of these functions causes undefined behavior. Even if the modification succeeds, the modified object can be overwritten by a subsequent call to the getenv()
, setlocale()
, localeconv()
, or strerror()
functions.
...
Bibliography
[ISO/IEC 9899:2011] | Section 7Subclause 7.11.1.1, "The setlocale Function"Section 7Subclause 7.22.4.6, "The getenv Function"Section 7Subclause 7.24.6.2, "The strerror Function" |
[Open Group 2004] | getenv setlocale localeconv |
...