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