Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

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 variable environ. In particular, if the optional envp argument to main() is present, it is not changed, and as a result may point to an obsolete copy of the environment (as may any other copy of environ).

This noncompliant code example accesses the envp pointer after calling setenv().

Code Block
bgColor#ffcccc
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
bgColor#ccccff
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 and wmain is a "frozen" copy of the current environment. If you subsequently change the environment via a call to putenv or _wputenv, the current environment (as returned by getenv / _wgetenv and the _environ / _wenviron variable) will change, but the block pointed to by envp will not change.

This noncompliant code example accesses the envp pointer after calling _putenvs()

Code Block
bgColor#ffcccc
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
bgColor#ccccff
_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
bgColor#ccccff
#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.

...