Mail Archives: cygwin/2010/10/29/18:11:15
On 10/29/2010 5:58 PM, Eric Blake wrote:
> On 10/29/2010 03:54 PM, Eric Blake wrote:
>> On 10/29/2010 03:44 PM, Ken Brown wrote:
>>> While trying to debug a timezone problem in the Cygwin build of emacs, I've come across a difference between Cygwin and Linux in the behavior of localtime with respect to TZ. Suppose I set TZ, call localtime, unset TZ, and call localtime again. On Cygwin, the second call to localtime re-uses the previous value of TZ. On Linux, localtime reverts to giving local information, just as if TZ had never been set. Here's a Simple Test Case:
>>>
>>> #include<time.h>
>>> #include<stdio.h>
>>>
>>> extern char **environ;
>
> Also, you should be including<unistd.h> for the declaration of environ,
> rather than declaring it yourself.
>
>>>
>>> void
>>> unset_TZ (void)
>>> {
>>> char **from, **to;
>>> for (to = from = environ; (*to = *from); from++)
>>> if (! (to[0][0] == 'T'&& to[0][1] == 'Z'&& to[0][2] == '='))
>>> to++;
>>> }
>>
>> Messing directly with environ is your problem. POSIX says that it is
>> only portable to traverse (but not modify) environ's contents, or to
>> completely assign a new array to environ. By going behind cygwin's
>> back, and not using unsetenv(), you have violated POSIX and can't expect
>> sane results.
>
> In particular:
>
> http://austingroupbugs.net/view.php?id=167
>
> If the application modifies the pointers to which environ
> points, the behavior of all interfaces described in the System
> Interfaces volume of POSIX.1-2008 is undefined.
>
>
> Conforming applications are required not to directly modify the
> pointers to which environ points, but to use only the setenv(),
> unsetenv() and putenv() functions, or assignment to environ
> itself, to manipulate the process environment. This constraint
> allows the implementation to properly manage the memory it
> allocates. This enables the implementation to free any space it
> has allocated to strings (and perhaps the pointers to them)
> stored in environ when unsetenv() is called. A C runtime start-up
> procedure (that which invokes main() and perhaps initializes
> environ) can also initialize a flag indicating that none of the
> environment has yet been copied to allocated storage, or that the
> separate table has not yet been initialized. If the application
> switches to a complete new environment by assigning a new value
> to environ, this can be detected by getenv(), setenv(), unsetenv()
> or putenv() and the implementation can at that point reinitialize
> based on the new environment. (This may include copying the
> environment strings into a new array and assigning environ to
> point to it.)
>
> In fact, for higher performance of getenv(), implementations
> that do not provide putenv() could also maintain a separate copy
> of the environment in a data structure that could be searched
> much more quickly (such as an indexed hash table, or a binary
> tree), and update both it and the linear list at environ when
> setenv() or unsetenv() is invoked. On implementations that do
> provide putenv(), such a copy might still be worthwhile but
> would need to allow for the fact that applications can directly
> modify the content of environment strings added with putenv().
> For example, if an environment string found by searching the
> copy is one that was added using putenv(), the implementation
> would need to check that the string in environ still has the
> same name (and value, if the copy includes values), and whenever
> searching the copy produces no match the implementation would
> then need to search each environment string in environ that
> was added using putenv() in case any of them have changed their
> names and now match. Thus each use of putenv() to add to the
> environment would reduce the speed advantage of having the copy.
>
> After page 772 line 25712 section exec, add two new paragraphs:
>
> Applications can change the entire environment in a single
> operation by assigning the environ variable to point to an array
> of character pointers to the new environment strings.
> After assigning a new value to environ, applications should
> not rely on the new environment strings remaining part of the
> environment, as a call to getenv(), [XSI]putenv(),[/XSI]
> setenv(), unsetenv() or any function that is dependent on an
> environment variable may, on noticing that environ has changed,
> copy the environment strings to a new array and assign environ
> to point to it.
>
> Any application that directly modifies the pointers to which the
> environ variable points has undefined behavior.
>
Thanks, Eric. I didn't know about any of this. (I was using a modification of a configure test from the emacs sources.) But I get the same behavior with the following revised test case:
#include <time.h>
#include <stdio.h>
int
main (void)
{
time_t now = time ((time_t *) 0);
printf ("TZ is initially unset; hour = %d\n", localtime (&now)->tm_hour);
putenv ("TZ=GMT0");
printf ("TZ=GMT0; hour = %d\n", localtime (&now)->tm_hour);
unsetenv("TZ");
printf ("TZ unset; hour = %d\n", localtime (&now)->tm_hour);
putenv ("TZ=PST8");
printf ("TZ=PST8; hour = %d\n", localtime (&now)->tm_hour);
unsetenv("TZ");
printf ("TZ unset again; hour = %d\n", localtime (&now)->tm_hour);
}
So the question remains whether this difference between Cygwin and Linux is a bug or by design.
Ken
--
Problem reports: http://cygwin.com/problems.html
FAQ: http://cygwin.com/faq/
Documentation: http://cygwin.com/docs.html
Unsubscribe info: http://cygwin.com/ml/#unsubscribe-simple
- Raw text -