Search code examples
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 modifing 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:

  • In my unsetenv_impl() implementation, is it necesary / proper to free the memory of removed environment string by free()?

  • If I don't free it, will it be a problem, or it won't take much memory thus could be ignored?


Tip:

putenv() won't duplicate the string, it just make global variable environ point to the string that pass to it.


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