On Tue, Jan 15, 2019 at 02:41:42PM -0500, Jeff King wrote:
> The more involved one (that doesn't pass along memory ownership) is
> something like:
>
> static struct hashmap env_cache;
>
> const char *getenv_safe(const char *name)
> {
>
> if (e = hashmap_get(&env_cache, name))
> return e->value;
>
> /* need some trickery to make sure xstrdup does not call getenv */
> e->value = xstrdup_or_null(getenv(name));
> e->name = xstrdup(name);
> hashmap_put(&env_cache, e);
>
> return e->value;
> }
>
> with a matching setenv_safe() to drop the hashmap entry. Come to think
> of it, this is really pretty equivalent to string-interning, which we
> already have a hashmap for. I think one could argue that string
> interning is basically just a controlled form of memory leaking, but
> it's probably a reasonable compromise in this instance (i.e., we expect
> to ask about a finite number of variables anyway; the important thing is
> just that we don't leak memory for the same variable over and over).
So actually, that's pretty easy to do without writing much code at all.
Something like:
#define xgetenv(name) strintern(getenv(name))
It means we're effectively storing the environment twice in the worst
case, but that's probably not a big deal. Unless we have a loop which
does repeated setenv()/getenv() calls, the strintern hashmap can't grow
without bound.
-Peff