...
Code Block |
---|
extern char **environ; /* ... */ int main(int argc, const char *argv[], const char *envp[]) { printf("environ: %p\n", environ); printf("envp: %p\n", envp); setenv("MY_NEW_VAR", "new_value", 1); puts("--Added MY_NEW_VAR--"); printf("environ: %p\n", environ); printf("envp: %p\n", envp); } |
Yieldsyields:
Code Block |
---|
% ./envp-environ environ: 0xbf8656ec envp: 0xbf8656ec --Added MY_NEW_VAR-- environ: 0x804a008 envp: 0xbf8656ec |
...
Wiki Markup |
---|
After a call to the POSIX {{setenv()}} function, or otheranother function that modifies the environment, the {{envp}} pointer may no longer reference the environment. POSIX states that \[[Open Group 04|AA. C References#Open Group 04]\] |
Unanticipated results may occur if
setenv()
changes the external variableenviron
. In particular, if the optionalenvp
argument tomain()
is present, it is not changed, and as a result may point to an obsolete copy of the environment (as may any other copy ofenviron
).
This noncompliant code example accesses the envp
pointer after calling setenv()
.
Code Block | ||
---|---|---|
| ||
int main(int argc, const char *argv[], const char *envp[]) { size_t i; if (setenv("MY_NEW_VAR", "new_value", 1) != 0) { /* Handle Errorerror */ } if (envp != NULL) { for (i = 0; envp[i] != NULL; i++) { if (puts(envp[i]) == EOF) { /* Handle Errorerror */ } } } return 0; } |
Because envp
may no longer points point to the current environment, this program has undefined behavior.
...
Code Block | ||
---|---|---|
| ||
extern char **environ; /* ... */ int main(int argc, const char *argv[]) { size_t i; if (setenv("MY_NEW_VAR", "new_value", 1) != 0) { /* Handle Errorerror */ } if (environ != NULL) { for (i = 0; environ[i] != NULL; i++) { if (puts(environ[i]) == EOF) { /* Handle Errorerror */ } } } return 0; } |
Noncompliant Code Example (Windows)
...
The environment block passed to
main
andwmain
is a "frozen" copy of the current environment. If you subsequently change the environment via a call toputenv
or_wputenv
, the current environment (as returned bygetenv
/_wgetenv
and the_environ
/_wenviron
variable) will change, but the block pointed to byenvp
will not change.
This noncompliant code example accesses the envp
pointer after calling _putenvs()
Code Block | ||
---|---|---|
| ||
int main(int argc, const char *argv[], const char *envp[]) { size_t i; if (_putenv_s("MY_NEW_VAR", "new_value") != 0) { /* Handle Errorerror */ } if (envp != NULL) { for (i = 0; envp[i] != NULL; i++) { if (puts(envp[i]) == EOF) { /* Handle Errorerror */ } } } return 0; } |
Because envp
no longer points to the current environment, this program fails to print the value of MY_NEW_VAR
.
...
Code Block | ||
---|---|---|
| ||
_CRTIMP extern char **_environ; /* ... */ int main(int argc, const char *argv[]) { size_t i; if (_putenv_s("MY_NEW_VAR", "new_value") != 0) { /* Handle Errorerror */ } if (_environ != NULL) { for (i = 0; _environ[i] != NULL; i++) { if (puts(_environ[i]) == EOF) { /* Handle Errorerror */ } } } return 0; } |
Compliant Solution
Note: if If you have a great deal of unsafe envp
code, you can save time in your remediation by aliasingreplacing. Change:
Code Block |
---|
int main(int argc, char *argv[], char *envp[]) { /* ... */ } |
To:with
Code Block | ||
---|---|---|
| ||
#if defined (_POSIX_) || defined (__USE_POSIX) extern char **environ; #define envp environ #else _CRTIMP extern char **_environ; #define envp _environ #endif int main(int argc, char *argv[]) { /* ... */ } |
...
Using the envp
environment pointer after the environment has been modified may can result in undefined behavior.
...