0

I'm trying to implement built-in function like setenv, getenv and unsetenv. All work well with getenv but i really don't how to free memory that i allocated with _setenv.

Here is my code for _setenv :

char *_setenv(const char *name, const char *value, int overwrite)
{
    long int i = -1;
    char *var = NULL;
    int var_len = 0, name_len = 0;
    char **new_env = NULL;

    if (name == NULL || value == NULL)
        return (NULL);
    var = _getenv(name);
    if (var != NULL && overwrite == 0)
        return (var);

    var_len = strlen(value);
    name_len = strlen(name);
    var = (char *)malloc(sizeof(char) * (name_len + var_len + 2));
    memcpy(var, name, name_len);
    strcat(var, "=");
    strncat(var, value, var_len);

    if (var != NULL && overwrite != 0)
        environ[i] = var;
    else
    {
        long int env_len = get_env_length(environ);

        new_env = (char **)malloc(sizeof(*new_env) * (env_len + 2));
        for (i = 0; i < env_len; i++)
        {
            int var_len = strlen(environ[i]);

            new_env[i] = (char *)malloc(sizeof(*new_env[i]) * var_len + 1);
            memcpy(new_env[i], environ[i], var_len);
            new_env[i][var_len + 1] = '\0';
        }
        new_env[env_len + 1] = var;
        new_env[env_len + 2] = NULL;
    }
    return (var);
}

I made this _free_env to free the allocated memory but it keep returning an error about invalid pointer:

int _free_env(void)
{
    int res = 0, i = 0;

    for (i = 0; environ[i]; i++)
        free(environ[i]);

    free(environ);
    return (res);
}

I guess it's about environ variables that i have not allocated myself, but since i need to free memory i allocate in the case i overwrite or add a variable, it is very difficult. Can you help me please ?

PS: _getenv is a my custom version of the built-in getenv and get_env_length is a function that get the number of variables in environ

Ryan Goss
  • 11
  • 3
  • You could just ignore it. Few, if any, programs do so much environment manipulation that the leakage would be anything to worry about in practice. Or you could engage the [Boehm GC](https://en.wikipedia.org/wiki/Boehm_garbage_collector) to perform any needed allocations and thereafter manage any freeing. (And then ignore it.) – John Bollinger Apr 18 '23 at 12:30
  • 1
    Is this supposed to work alongside the existing `setenv` and `getenv`, or are your `_setenv` and `_getenv` replacing them? – Useless Apr 18 '23 at 12:30
  • If you need to manage it manually then you could consider managing your own pool(s) of memory for environment variables instead of allocating memory individually for each one. Then register an [exit handler](https://man7.org/linux/man-pages/man3/atexit.3.html) that frees all the pools. – John Bollinger Apr 18 '23 at 12:33
  • For full generality, you may need to implement a set of Boolean flags somewhere that tell you, for each variable in the environment, whether it comes from the originally passed-in environment, or was set by the user via a call to `putenv` or `setenv`. (But then one must also ask: is this complexity, and the extra code space it will require, even worth it?) – Steve Summit Apr 18 '23 at 12:46
  • @Useless It's supposed to replace them in my program. I would be using them instead of the existing `getenv` and `setenv`. But i dont think there will any problem to use my `_getenv` or `_setenv` alongside with the existing `getenv` and `setenv` – Ryan Goss Apr 18 '23 at 12:48
  • @JohnBollinger Exactly, I thought about creating my own `environ` variable (`environe`). Then I should initializing that variable with a function that copy environ in environe, so instead of manipulating environ, i work with environe and free that environe at the end of the program, but i don't know how to impleting correctly taht idea since i lack knowledge about the extern keyword (declaration and initialization seems a bit complicated). When i tried i got errot about undefined reference to my extern variable and also an error about relocation in read-only section – Ryan Goss Apr 18 '23 at 12:56
  • @SteveSummit that great idea. Keep track of the modified one between the variables and only free these. Like an array of int with the same length as environ where values are 0 for unmodified and 1 for modified, these latter should be freed – Ryan Goss Apr 18 '23 at 12:59
  • `memcpy(var, name, name_len);` does not copy the `0`-terminator of the string to the destination, so `strcat(var, "=");` afterwards is undefined behavior. `memcpy(var, name, name_len); strcat(var, "="); strncat(var, value, var_len);` can be rewritten without this bug as `sprintf(var, "%s=%s", name, value);`. – mch Apr 18 '23 at 13:25
  • thanks @mch I'll take that into account and re-code the function – Ryan Goss Apr 18 '23 at 18:16

0 Answers0