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
specification.

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
head:
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().

Sean
  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/
--
scf@xxxxxxxxxxx



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