Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

putenv / POSIX question

11 views
Skip to first unread message

David Shaw

unread,
Jan 19, 1999, 3:00:00 AM1/19/99
to
Hi everyone,

Here's a sample program that uses putenv. Some references I have found
say that putenv just points the environment to the string that you pass
it, and thus you cannot modify/free that string. Other references say no
such thing.

The following program works "correctly" (i.e. prints both var1 and var2)
on Linux (w/libc6) and the 44BSDs. It only shows the var2 line in Solaris
(both 2.5 and 2.6).

Now, I undestand clearly what is happening, and I understand why it
doesn't work on Solaris. What I want to know is: who is right? Does
POSIX dictate anything on this subject? (the Linux and 44BSD man page for
putenv says it is POSIX compliant, and the Solaris one doesn't).

Finally, if POSIX says that Linux and the 44BSDs are right, is there an
easy way (a #define, perhaps) to make Solaris Do The Right Thing?

Thanks very much!

David

#include <stdlib.h>
#include <stdio.h>

int main(int argc, char *argv[])
{
char string[10];
char *var1,*var2;

strcpy(string,"var1=foo");
putenv(string);
strcpy(string,"var2=bar");
putenv(string);

var1=getenv("var1");
var2=getenv("var2");

if(var1!=NULL)
printf("var1=%s\n",var1);

if(var2!=NULL)
printf("var2=%s\n",var2);

return 0;
}

--
David Shaw | dshaw (at) cs.jhu.edu | WWW http://www.cs.jhu.edu/~dshaw/
+--------->> remove broken part of my address to actually mail me <<--------+
"There are two major products that come out of Berkeley: LSD and UNIX.
We don't believe this to be a coincidence." - Jeremy S. Anderson

J. Benz

unread,
Jan 19, 1999, 3:00:00 AM1/19/99
to
Just ran into this recently - on DEC Alpha. It exhibits (if I read your post
correctly) the same behavior as Solaris. More completely, it passes a pointer to
the string to the environment, and you can then change the environment by simply
changing the string the pointer points to. It's very easy to prove to yourself -
just:

char *str = "VAR=foo";
char *str2;

putenv( str );

str = "bar";

str2 = getenv( "VAR" );

printf( "%s\n", str2 );

This dumps core, because getenv() can't find "VAR=" anywhere in the environment
anymore, and it doesn't match on "bar" either. So str2 is NULL.

The man page claims 'XPG4 and XPG4-Unix' in the standards section, but nothing
about POSIX. I would suspect that all these standards leave this as
'implementation defined'. But as for making Solaris do 'the right thing' - the
'right thing' is not always the intuitive thing. I would suggest coding to what
you would call 'the wrong thing' and make sure it also works on Linux. Since you
now know that at least two common compilers do 'the wrong thing', it behooves you
to be as portable as possible.

Joerg Schilling

unread,
Jan 19, 1999, 3:00:00 AM1/19/99
to
Solaris is right: it is UNIX98 compatible.

From the UNIX98 definitions putenv() APPLICATION USAGE:

A potential error is to call putenv() with an automatic variable
as the argument, then return from the calling function while string
is still part of the environment.

This should make it clear that the definition for putenv() expexts that
the string is not allocated and duplicted but directly inlcuded into the
environment.

Joerg

In article <782dcl$1...@foobar.cs.jhu.edu>,

--
EMail:jo...@schily.isdn.cs.tu-berlin.de (home) Jörg Schilling D-13353 Berlin
j...@cs.tu-berlin.de (uni) If you don't have iso-8859-1
schi...@fokus.gmd.de (work) chars I am J"org Schilling
URL: http://www.fokus.gmd.de/usr/schilling ftp://ftp.fokus.gmd.de/pub/unix

Geoff Clare

unread,
Jan 22, 1999, 3:00:00 AM1/22/99
to
ds...@no.spam.thanks (David Shaw) writes:

>The following program works "correctly" (i.e. prints both var1 and var2)
>on Linux (w/libc6) and the 44BSDs. It only shows the var2 line in Solaris
>(both 2.5 and 2.6).

>Now, I undestand clearly what is happening, and I understand why it
>doesn't work on Solaris. What I want to know is: who is right? Does
>POSIX dictate anything on this subject? (the Linux and 44BSD man page for
>putenv says it is POSIX compliant, and the Solaris one doesn't).

I'm pretty sure that putenv() is not in any of the POSIX standards, so
it seems odd that Linux and 44BSD claim compliance in their man pages.
Maybe it is being added in one of the POSIX .1x drafts.

The Single UNIX spec. says:

`The _string_ argument should point to a string of the form
"name=value" ... the string pointed to by _string_ becomes part
of the environment, so altering the string will change the
environment.'

This means the behaviour you observed on Solaris is "correct", and the
Linux and 44BSD systems you tried do not have a UNIX95-compliant putenv().

> char string[10];
> char *var1,*var2;

> strcpy(string,"var1=foo");
> putenv(string);
> strcpy(string,"var2=bar");
> putenv(string);

> var1=getenv("var1");
> var2=getenv("var2");

This test program could actually give a "false pass" on some systems,
because getenv() is allowed to return a pointer to internal static data.
To be sure you are seeing what is actually in the environment, you should
print the value returned by the first getenv() before you call it again.

--
Geoff Clare <g...@root.co.uk>
UniSoft Limited, London, England.

J. Benz

unread,
Jan 22, 1999, 3:00:00 AM1/22/99
to

Geoff Clare wrote:

> This means the behaviour you observed on Solaris is "correct", and the
> Linux and 44BSD systems you tried do not have a UNIX95-compliant putenv().
>
> > char string[10];
> > char *var1,*var2;
>
> > strcpy(string,"var1=foo");
> > putenv(string);
> > strcpy(string,"var2=bar");
> > putenv(string);
>
> > var1=getenv("var1");
> > var2=getenv("var2");
>
> This test program could actually give a "false pass" on some systems,
> because getenv() is allowed to return a pointer to internal static data.
> To be sure you are seeing what is actually in the environment, you should
> print the value returned by the first getenv() before you call it again.

Errr, Geoff,

I would appreciate proper attribution of my posts in the future.

This sample program is *supposed* to demonstrate the "false pass" you describe
- if you had read the post it was embedded in you'd know that. And as for
'some systems', that, too, was the point of the original post - to find out
whether *your* system does or does not handle the environment in the standard
way.


Joerg Schilling

unread,
Jan 23, 1999, 3:00:00 AM1/23/99
to
In article <36A8BF28...@danet.com>, J. Benz <be...@danet.com> wrote:
>Geoff Clare wrote:
>
>> This means the behaviour you observed on Solaris is "correct", and the
>> Linux and 44BSD systems you tried do not have a UNIX95-compliant putenv().
>>
>> > char string[10];
>> > char *var1,*var2;
>>
>> > strcpy(string,"var1=foo");
>> > putenv(string);
>> > strcpy(string,"var2=bar");
>> > putenv(string);
>>
>> > var1=getenv("var1");
>> > var2=getenv("var2");
>>
>> This test program could actually give a "false pass" on some systems,
>> because getenv() is allowed to return a pointer to internal static data.
>> To be sure you are seeing what is actually in the environment, you should
>> print the value returned by the first getenv() before you call it again.
...

>This sample program is *supposed* to demonstrate the "false pass" you describe
>- if you had read the post it was embedded in you'd know that. And as for
>'some systems', that, too, was the point of the original post - to find out
>whether *your* system does or does not handle the environment in the standard
>way.

Note that as I mentioned earlier, the standard way (as documented in the single
UNIX specification http://www.opengroup.org/onlinepubs/7908799/xsh/putenv.html)
is to insert the argument of putenv() into the allocated environ array.

The program included above is a documented misusage.

Joerg

Geoff Clare

unread,
Jan 26, 1999, 3:00:00 AM1/26/99
to
"J. Benz" <be...@danet.com> writes:

>Geoff Clare wrote:

>> > char string[10];
>> > char *var1,*var2;
>>
>> > strcpy(string,"var1=foo");
>> > putenv(string);
>> > strcpy(string,"var2=bar");
>> > putenv(string);
>>
>> > var1=getenv("var1");
>> > var2=getenv("var2");
>>
>> This test program could actually give a "false pass" on some systems,
>> because getenv() is allowed to return a pointer to internal static data.
>> To be sure you are seeing what is actually in the environment, you should
>> print the value returned by the first getenv() before you call it again.

>Errr, Geoff,

>I would appreciate proper attribution of my posts in the future.

Huh? The attribution I gave was entirely correct. The text I quoted was
from David Shaw's article, not yours.

>This sample program is *supposed* to demonstrate the "false pass" you describe

No. The program was supposed to test the behaviour of putenv(). I pointed
out that the code makes an assumption about the behaviour of getenv() that
could affect the output it produces on some systems.

Thinking about it some more, perhaps saying "false pass" wasn't quite
right. On a system where the putenv() test should fail (because it
copies the string before putting it in the environment), but getenv()
returns a pointer to internal static data, the output will be:

var1=bar
var2=bar

which is different from both the expected "pass" output (var1 not set,
var2=bar) and the expected "fail" output (var1=foo, var2=bar).

0 new messages