Subject: Re: Memory leak in setenv(3) ?
To: None <paul@whooppee.com>
From: Simon Burge <simonb@wasabisystems.com>
List: current-users
Date: 05/30/2003 12:50:45
Paul Goyette wrote:
> I've been looking for a while to find a memory leak in one of my
> programs, and I think I've finally narrowed things down to, of all
> things, setenv(3) (and unsetenv(3), too)!
>
> It seems that if you set an environment variable, _and_ you have the
> overwrite flag set, it will reuse the existing value's space if and
> only if the new value is not longer than the old value.
>
> In all other cases (new value is longer, overwrite not set, or no
> previous value exists), a new chunk of memory is malloc(3)d; if there
> was a previous value, it is conveniently forgotten without ever being
> free(3)d! Similarly, if you unsetenv(3) a variable, the value is just
> discarded without being free(3)d.
>
> Granted, this probably wouldn't affect too many people, since one
> usually doesn't keep redefining the same environment variable over and
> over. But in my case, I have a server that needs to fairly frequently
> display timestamps to users that connect, and each user has his/her
> own TZ value. So, in order to make localtime(3) use the correct TZ, I
> need to continually update the environment variable.
>
> Wouldn't it make sense that, if we're going to use malloc(3) to get
> space for the environment variables, we would properly use realloc(3)
> and free(3) to keep track of space no longer being used by them?
I believe it's not that simple. See
http://sources.redhat.com/ml/cygwin/2000-07/msg00892.html for example.
See also http://mail-index.netbsd.org/tech-userlevel/2001/12/27/0002.html :-)
> Just as an aside, we _do_ use malloc(3) and realloc(3) to manage the
> list of pointers to environment variable values! :)
I've got the following in a program I use (a multi-timezone hack for
xclock). This is near the start of the program:
/*
* XXX: The longestlen, longest, setenv business is described
* in Clock.c - look for
* XXX - this is not pretty
*/
int i, longestlen;
char *longest;
ntimezones = argc - 1;
timezones = (char **)malloc(argc * sizeof(char *));
longestlen = 0;
for (i = 0; i < ntimezones; i++) {
timezones[i] = argv[i + 1];
if (strlen(timezones[i]) > longestlen) {
longest = timezones[i];
longestlen = strlen(timezones[i]);
}
}
setenv("TZ", longest, 1);
and this is in the loop where I want to call localtime with different
timezones:
#ifdef want_memory_leak
setenv("TZ", tz, 1);
#else
/* XXX - this is not pretty! but setenv() leaks memory :-( */
char *envptr;
envptr = getenv("TZ");
strcpy(envptr, tz);
#endif
tm = *localtime(&time_value);
Not nice, but get's the job done. Having something like a
localtime_tz(3) with an extra arg for the timezone would be nice...
Simon.
--
Simon Burge <simonb@wasabisystems.com>
NetBSD Support and Service: http://www.wasabisystems.com/