Date: Thu, 3 Oct 1996 10:11:54 +0200 (IST) From: Eli Zaretskii To: djgpp-workers AT delorie DOT com Subject: More defensive `putenv' Message-Id: Mime-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII It seems that other implementations of `putenv' tolerate setting `environ' to something else, e.g. to start with a clean environment. At least two programs in the GNU Sh-utils have something like this: char *dummy_environ[1]; environ = dummy_environ; environ[0] = NULL; Our `putenv' of course gets totally confused by this. So here are some changes to make it more defensive, and also support ``putenv("foobar")'' (meaning delete "foobar") which some Sh-utils need. *** src/libc/compat/stdlib/putenv.c~2 Sat Aug 10 16:08:36 1996 --- src/libc/compat/stdlib/putenv.c Tue Oct 1 21:15:54 1996 *************** *** 15,20 **** --- 15,21 ---- */ extern char **environ; + static char **prev_environ = NULL; /* to know when it's safe to call `free' */ static int ecount = -1; static int emax = -1; static int putenv_bss_count = -1; *************** *** 37,60 **** { int vlen = strlen(val); char *epos = strchr(val, '='); ! int nlen = epos - val + 1; int eindex; ! if (putenv_bss_count != __bss_count) { - putenv_bss_count = __bss_count; for (ecount=0; environ[ecount]; ecount++); emax = ecount; /* Bump the count to a value no function has yet seen, even if they were dumped with us. */ __environ_changed++; } - if (epos == 0) - return -1; - for (eindex=0; environ[eindex]; eindex++) ! if (strncmp(environ[eindex], val, nlen) == 0) { char *oval = environ[eindex]; --- 38,73 ---- { int vlen = strlen(val); char *epos = strchr(val, '='); ! /* Feature: VAL without a `=' means delete the entry. GNU `putenv' ! works that way, and `env' from GNU Sh-utils counts on this behavior. */ ! int nlen = epos ? epos - val + 1 : vlen; int eindex; ! /* Force recomputation of the static counters. ! ! The second condition of the next if clause covers the case that ! somebody pointed environ to another array, which invalidates ! `ecount' and `emax'. This can be used to change the environment ! to something entirely different, or to effectively discard it ! altogether. GNU `env' from Sh-utils does just that. */ ! if (putenv_bss_count != __bss_count ! || environ != prev_environ) { for (ecount=0; environ[ecount]; ecount++); emax = ecount; /* Bump the count to a value no function has yet seen, even if they were dumped with us. */ __environ_changed++; + if (putenv_bss_count != __bss_count) + { + putenv_bss_count = __bss_count; + prev_environ = environ; /* it's malloced by crt1.c */ + } } for (eindex=0; environ[eindex]; eindex++) ! if (strncmp(environ[eindex], val, nlen) == 0 ! && (epos || environ[eindex][nlen] == '=')) { char *oval = environ[eindex]; *************** *** 92,103 **** { char **enew; emax += 10; ! enew = (char **)malloc(emax * sizeof(char **)); if (enew == 0) return -1; memcpy(enew, environ, ecount * sizeof(char *)); ! free(environ); environ = enew; } environ[ecount] = (char *)malloc(vlen+1); --- 105,120 ---- { char **enew; emax += 10; ! enew = (char **)malloc(emax * sizeof(char *)); if (enew == 0) return -1; memcpy(enew, environ, ecount * sizeof(char *)); ! /* If somebody set environ to another array, we can't ! safely free it. Better leak memory than crash. */ ! if (environ == prev_environ) ! free(environ); environ = enew; + prev_environ = environ; } environ[ecount] = (char *)malloc(vlen+1);