Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

Re: putenv()/environ bug

On Wed, 25 Jul 2007, Peter Stephenson wrote:

On Wed, 25 Jul 2007 10:09:22 -0500 (CDT)
"Sean C. Farley" <scf@xxxxxxxxxxx> wrote:
As noticed here following a change in FreeBSD's *env() functions, zsh
is mixing *env() (putenv() in this case) functions with direct access
to the environ variable's contents against the IEEE Std 1003.1

BTW, is there a particular reason the standard *env() functions
cannot be used for all operations to environ if found?

There's a long history of fiddling with these for problems on various
systems, so I'm a little unwilling to change it without some guidance.

For example,

    * Under Cygwin we must use putenv() to maintain consistency.
    * Unfortunately, current version (1.1.2) copies argument and may
    * silently reuse existing environment string. This tries to
    * check for both cases

I understand.

This is a little confusing since the code in question (addenv in
params.c) doesn't actually use putenv().

Legacy comments are only meant to throw developers off the track.  :)

Given we manipulate environ quite a lot anyway, is there any harm in
using only the zsh versions of zgetenv() and zputenv()?  There's a
getenv() instead of a zgetenv() in init.c:  I think that was just a
typo by me.

*code snipped*

Unfortunately, this does not fix the problem.  unsets are only affecting
the zsh environment but not environ.  For example, here is a reduced set
of calls to duplicate it:

export FOO=BAR
exec zsh
unset FOO
env | grep FOO
echo $FOO

The call to env (/bin/env) will show "FOO=BAR" while the echo will not.

It is difficult to decide what to do.  Here are some thoughts in my
1. Telling zsh that putenv() does not exist forces it to manipulate a
   new copy of environ (zputenv() and createparamtable()).  This almost
   (see #2) prevents it from mixing *env() functions with direct changes
   to environ.
2. To truly prevent mixing, zsh may need to be told getenv() does not
   exist.  This way it is not directly (see #3) calling any *env()
   functions.  I have not seen a need (any bug reports) for this.
3. There may be other libc functions that call *env() functions.  For
   example, setlocale() calls getenv().  If all setlocale() calls are
   done prior to any manipulation of environ, then this should be safe.
4. The FreeBSD *env() code can detect if environ != prevEnviron but not
   if environ[x] has changed.
5. OpenSolaris does some similar stuff with its *env() functions[1].
   Somebody may want to check if it is also affected.
6. The FreeBSD port[2] should have a fix relatively soon to avoid this
   by telling configure not to look for putenv().

  1. http://cvs.opensolaris.org/source/xref/clearview/usr/src/lib/libc/port/gen/getenv.c
  2. http://www.freebsd.org/cgi/cvsweb.cgi/ports/shells/zsh/

Messages sorted by: Reverse Date, Date, Thread, Author