C99 says The C standard says getenv()
has the following behavior [ISO/IEC 9899:19992011]:
The getenv function 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 the getenv function.
Consequently, it is best not to store this pointer, as it may be overwritten by a subsequent call to the getenv()
function or invalidated as a result of changes made to the environment list through calls to putenv()
, setenv()
, or other means. Storing the pointer for later use can result in a dangling pointer or a pointer to incorrect data. This string should be referenced immediately and discarded; if later use is anticipated, the string should be copied , so the copy can be safetly safely referenced as needed.
The getenv()
function is not thread-safe. Make sure to address any possible race conditions resulting from the use of this function.
...
Code Block | ||||
---|---|---|---|---|
| ||||
char *tmpvar;
char *tempvar;
tmpvar = getenv("TMP");
if (!tmpvar) return -1;
tempvar = getenv("TEMP");
if (!tempvar) return -1;
if (strcmp(tmpvar, tempvar) == 0) {
if (puts("TMP and TEMP are the same.\n") == EOF) {
/* Handle error */
}
}
else {
if (puts("TMP and TEMP are NOT the same.\n") == EOF) {
/* Handle error */
}
}
|
...
Code Block | ||||
---|---|---|---|---|
| ||||
char *tmpvar;
char *tempvar;
size_t requiredSize;
getenv_s(&requiredSize, NULL, 0, "TMP");
tmpvar = (char *)malloc(requiredSize * sizeof(char));
if (!tmpvar) {
/* Handle error */
}
getenv_s(&requiredSize, tmpvar, requiredSize, "TMP" );
getenv_s(&requiredSize, NULL, 0, "TEMP");
tempvar = (char *)malloc(requiredSize * sizeof(char));
if (!tempvar) {
free(tmpvar);
tmpvar = NULL;
/* Handle error */
}
getenv_s(&requiredSize, tempvar, requiredSize, "TEMP" );
if (strcmp(tmpvar, tempvar) == 0) {
if (puts("TMP and TEMP are the same.\n") == EOF) {
/* Handle error */
}
}
else {
if (puts("TMP and TEMP are NOT the same.\n") == EOF) {
/* Handle Error */
}
}
free(tmpvar);
tmpvar = NULL;
free(tempvar);
tempvar = NULL;
|
...
Windows also provides the _dupenv_s()
and _wdupenv_s()
functions for getting a value from the current environment [MSDN]. The _dupenv_s()
function searches the list of environment variables for a specified name. If the name is found, a buffer is allocated; the variable's value is copied into the buffer, and the buffer's address and number of elements are returned. By allocating the buffer itself, _dupenv_s()
and _wdupenv_s()
provide a more convenient alternative to getenv_s()
and _wgetenv_s()
.
...
Code Block | ||||
---|---|---|---|---|
| ||||
char *tmpvar;
char *tempvar;
size_t len;
errno_t err = _dupenv_s(&tmpvar, &len, "TMP");
if (err) return -1;
err = _dupenv_s(&tempvar, &len, "TEMP");
if (err) {
free(tmpvar);
tmpvar = NULL;
return -1;
}
if (strcmp(tmpvar, tempvar) == 0) {
if (puts("TMP and TEMP are the same.\n") == EOF) {
/* Handle error */
}
}
else {
if (puts("TMP and TEMP are NOT the same.\n") == EOF) {
/* Handle error */
}
}
free(tmpvar);
tmpvar = NULL;
free(tempvar);
tempvar = NULL;
|
...
POSIX provides the strdup()
function, which can make a copy of the environment variable string [Open Group 2004]. The strdup()
function is also included in ISO/IEC PDTR 24731-2 in Extensions to the C Library—Part II [ISO/IEC PDTR TR 24731-2:2010].
Code Block | ||||
---|---|---|---|---|
| ||||
char *tmpvar;
char *tempvar;
const char *temp = getenv("TMP");
if (temp != NULL) {
tmpvar = strdup(temp);
if (tmpvar == NULL) {
/* Handle error */
}
}
else {
return -1;
}
temp = getenv("TEMP");
if (temp != NULL) {
tempvar = strdup(temp);
if (tempvar == NULL) {
free(tmpvar);
tmpvar = NULL;
/* Handle error */
}
}
else {
free(tmpvar);
tmpvar = NULL;
return -1;
}
if (strcmp(tmpvar, tempvar) == 0) {
if (puts("TMP and TEMP are the same.\n") == EOF) {
/* Handle error */
}
}
else {
if (puts("TMP and TEMP are NOT the same.\n") == EOF) {
/* Handle error */
}
}
free(tmpvar);
tmpvar = NULL;
free(tempvar);
tempvar = NULL;
|
...
This compliant solution uses only the C99 C malloc()
and strcpy()
functions to copy the string returned by getenv()
into a dynamically allocated buffer.
Code Block | ||||
---|---|---|---|---|
| ||||
char *tmpvar;
char *tempvar;
const char *temp = getenv("TMP");
if (temp != NULL) {
tmpvar = (char *)malloc(strlen(temp)+1);
if (tmpvar != NULL) {
strcpy(tmpvar, temp);
}
else {
/* Handle error */
}
}
else {
return -1;
}
temp = getenv("TEMP");
if (temp != NULL) {
tempvar = (char *)malloc(strlen(temp)+1);
if (tempvar != NULL) {
strcpy(tempvar, temp);
}
else {
free(tmpvar);
tmpvar = NULL;
/* Handle error */
}
}
else {
free(tmpvar);
tmpvar = NULL;
return -1;
}
if (strcmp(tmpvar, tempvar) == 0) {
if (puts("TMP and TEMP are the same.\n") == EOF) {
/* Handle error */
}
}
else {
if (puts("TMP and TEMP are NOT the same.\n") == EOF) {
/* Handle error */
}
}
free(tmpvar);
tmpvar = NULL;
free(tempvar);
tempvar = NULL;
|
...
Tool | Version | Checker | Description | |
---|---|---|---|---|
Section | Compass/ROSE |
|
|
|
Related Guidelines
CERT C++ Secure Coding Standard: ENV00-CPP. Do not store the pointer to the string returned by getenv()
ISO/IEC 9899:19992011 Section 7.2022.4, "Communication with the environment"
ISO/IEC TR 17961 (Draft) Using an object overwritten by getenv, localeconv, setlocale, and strerror [libuse]
Bibliography
[MSDN] _dupenv_s()
and _wdupenv_s()
, getenv_s()
, _wgetenv_s()
[Open Group 2004] Chapter 8, and "Environment Variables," , strdup
[Viega 2003] Section 3.6, "Using Environment Variables Securely"
...