Main Content

Environment pointer invalidated by previous operation

Call to setenv or putenv family function modifies environment pointed to by pointer

Description

This defect occurs when you use the third argument of main() in a hosted environment to access the environment after an operation modifies the environment. In a hosted environment, many C implementations support the nonstandard syntax:

main (int argc, char *argv[], char *envp[])
A call to a setenv or putenv family function modifies the environment pointed to by *envp.

Risk

When you modify the environment through a call to a setenv or putenv family function, the environment memory can potentially be reallocated. The hosted environment pointer is not updated and might point to an incorrect location. A call to this pointer can return unexpected results or cause an abnormal program termination.

Fix

Do not use the hosted environment pointer. Instead, use global external variable environ in Linux®, _environ or _wenviron in Windows®, or their equivalent. When you modify the environment, these variables are updated.

Examples

expand all

#include <stdio.h>
#include <stdlib.h>

extern int check_arguments(int argc, char **argv, char **envp);
extern void use_envp(char **envp);

/* envp is from main function */
int func(char **envp) 
{
    /* Call to setenv may cause environment
     *memory to be reallocated 
     */
    if (setenv(("MY_NEW_VAR"),("new_value"),1) != 0) 
    {
        /* Handle error */
        return -1;
    }
    /* envp not updated after call to setenv, and may
     *point to incorrect location.
     **/
    if (envp != ((void *)0)) { 
        use_envp(envp);
/* No defect on second access to
*envp because defect already raised */
    }
    return 0;
}

void  main(int argc, char **argv, char **envp)
{
    if (check_arguments(argc, argv, envp))
    {
        (void)func(envp);
    }
}

In this example, envp is accessed inside func() after a call to setenv that can reallocate the environment memory. envp can point to an incorrect location because it is not updated after setenv modifies the environment. No defect is raised when use_envp() is called because the defect is already raised on the previous line of code.

Correction — Use Global External Variable environ

One possible correction is to access the environment by using a variable that is always updated after a call to setenv. For instance, in the following code, the pointer envp is still available from main(), but the environment is accessed in func() through the global external variable environ.

#include <stdio.h>
#include <stdlib.h>
extern char **environ;

extern int check_arguments(int argc, char **argv, char **envp);
extern void use_envp(char **envp);

int func(void)
{
    if (setenv(("MY_NEW_VAR"), ("new_value"),1) != 0) {
        /* Handle error */
        return -1;
    }
  /* Use global external variable environ
   *which is always updated after a call to setenv */
    
    if (environ != NULL) { 
        use_envp(environ);
    }
    return 0;
}

void  main(int argc, char **argv, char **envp)
{
    if (check_arguments(argc, argv, envp))
    {
        (void)func();
    }
} 

Result Information

Group: Programming
Language: C | C++
Default: On for handwritten code, off for generated code
Command-Line Syntax: INVALID_ENV_POINTER
Impact: Medium

Version History

Introduced in R2018a