This is the mail archive of the cygwin mailing list for the Cygwin project.

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: localtime and TZ

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:
>     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>

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);
  printf ("TZ unset; hour = %d\n", localtime (&now)->tm_hour);
  putenv ("TZ=PST8");
  printf ("TZ=PST8; hour = %d\n", localtime (&now)->tm_hour);
  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.


Problem reports:
Unsubscribe info:

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]