cmemory-managementsetenv

c - unsetenv() implementation, is it necessary to free memory?


As TLPI exercise 6-3 required, I made an implementation of setenv() and unsetenv() using putenv(), getenv() and via modifying the environ variable directly.

Code:

// setenv() / unsetenv() impl
// TLPI exercise 6-3

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>

#define ENV_SEP '='
extern char **environ;

// setenv() impl using putenv() & getenv()
int setenv_impl(const char * name , const char * value , int overwrite ) {
    if(!overwrite && getenv(name)) { // exists & don't overwrite
        return 0;
    } else {
        // construct the new variable
        char *env_var = malloc(strlen(name) + strlen(value) + 2);
        strcpy(env_var, name);
        env_var[strlen(name)] = ENV_SEP;
        strcpy(env_var+(strlen(name)+1), value);

        int result = putenv(env_var);
        if(result==0) {
            return 0;
        } else {
            errno = result;
            return -1;
        }
    }
}

// unsetenv() impl via modifing environ directly,
int unsetenv_impl(const char * name ) {
    char **ep, **sp;
    size_t len;

    len = strlen(name);
    for(ep = environ; *ep != NULL;) {
        if(strncmp(*ep, name, len)==0 && (*ep)[len] == ENV_SEP) {
            // shift all successive elements back 1 step,
            for(sp=ep; *sp != NULL; sp++) {
                *sp = *(sp+1);
            }
        } else {
            ep++;
        }
    }

    return 0;
}

// setenv_impl() test
int setenv_impl_test() {
    char *key = "name";

    setenv_impl(key,"Eric", 1);
    printf("%s\n", getenv(key));

    setenv_impl(key,"Eric2", 0);
    printf("%s\n", getenv(key));

    setenv_impl(key,"Eric3", 1);
    printf("%s\n", getenv(key));
    
    return 0;
}

// unsetenv_impl() test
int unsetenv_impl_test() {
    char *key = "name";

    setenv_impl(key,"Eric", 1);
    printf("%s\n", getenv(key));

    unsetenv_impl(key);

    char *val = getenv(key);
    printf("%s\n", val==NULL?"NULL":getenv(key));
    
    return 0;
}

int main(int argc, void *argv[]) {
    // setenv_impl_test();
    unsetenv_impl_test();

    return 0;
}

In my setevn_impl(), I use malloc() to allocate memory for new environment variable.

But I don't know how the memory of process's default environment allocated.

My question is:


Tip:

putenv() won't duplicate the string; it just makes the global variable environ point to the string that is passed to it. That means the string you pass to putenv() must remain valid after putenv() returns.


Solution

  • In your case it is not necessary if you don't plan to set your environment variables very frequently leading to exhaust of your memory resources.

    But it would be great if you always deallocate resources after you are done with using them, be it file handles/memory/mutexs. By doing so you will not make that sort of mistake when building servers.

    Some servers are expected to run 24x7. In those cases, any leak of any sort means that your server will eventually run out of that resource and hang/crash in some way. A short utility program, ya a leak isn't that bad. Any server, any leak is death. Do yourself a favor. Clean up after yourself. It's a good habit