Search code examples
arrayscmemory-managementoperating-system

Global variable needs to be passed as a parameter


I have a function that is copying the contents of the envp array that contains the global variables. The function is successful in copying the contents, however, when it returns, it seems like the array pointer is pointing somewhere else altogether.

#include <stdio.h>
#include <string.h>

// allow up to 64 environment variables
#define MAXENV 64

// local envp copy
char *envp_copy[MAXENV];

// current size of envp_copy
int envp_size = 0;

void copy_envp(char *envp[])
{
    for (long i = 0; i <= MAXENV; i++)
    {
        if (envp[i] == NULL)
        {
            envp_copy[i] = NULL;
            break;
        }
        envp_copy[i] = strdup(envp[i]);
        envp_size++;
    }
    for (int i = 0; i < envp_size; i++)
    {
        printf("%s\n", envp_copy[i]);
    }
}

int main(int argc, char *argv[], char *envp[], char *envp_copy[])
{
    copy_envp(envp);
    for (int i = 0; i < envp_size; i++)
    {
        printf("%s\n", envp_copy[i]);
    }
}

I know that if I change the copy_envp function to take the array as variable

void copy_envp(char *envp[], char *envp_copy[]);

Then everything works as expected. But I am struggling to understand why the array has to be passed in as a parameter, even though it was declared globally.


Solution

  • The C standard defines main() as taken either 0 or 2 arguments, or an "implementation-defined" manner and I only know of a 3rd argument with the char *environment[] and not a of a 4th argument which in your program shadows the global variable.

    Here is an implementation that avoids the global variable and addresses the memory leak (of the strings being strdup()). It also addresses the out of bound access; i = 0; i <= MAXENV is MAXENV + 1 loop iterations.

    #define _POSIX_C_SOURCE 200809L
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    #define MAXENV 64
    
    char **copy_envp(const char *env[]) {
        char **copy = malloc(sizeof *copy * (MAXENV+1));
        if(!copy) return NULL;
        int i = 0;
        for(; i < MAXENV && env[i]; i++)
            copy[i] = strdup(env[i]);
        copy[i] = NULL;
        // optionally shrink the copy to size
        char **tmp = realloc(copy, sizeof *copy * (i+1));
        return tmp ? tmp : copy;
    }
    
    int main(int argc, char *argv[], char *envp[]) {
        char **envp_copy = copy_envp((const char **) envp);
        if(!envp_copy) {
            printf("copy_envp empty or failed\n");
            return 1;
        }
        for (int i = 0; envp_copy[i]; i++) {
            printf("%s\n", envp_copy[i]);
            free(envp_copy[i]);
        }
        free(envp_copy);
    }