strftime("%Z") invalidated by TZ change: is this a fair restriction?

Jonathan Lennox lennox at cs.columbia.edu
Mon Jun 11 20:01:10 UTC 2001


This is an issue that occured to me in the process of converting tzcode to
support my proposed thread-safe API.

I think the following restriction is necessary to the POSIX 200x spec.

  If a 'struct tm' broken-down time structure is created by localtime() or
  localtime_r(), or modified by mktime(), and the value of the "TZ"
  environment variable is subsequently modified, the results of the %Z and
  %z strftime() and wcsftime() conversion specifiers are undefined, when
  strftime() or wcsftime() is called with such a broken-down time structure.

  If the broken-down time structure is subsequently modified by a successful
  call to mktime(), the results of these conversion specifiers are once
  again defined.

  If a 'struct tm' broken-down time structure is modified by gmtime(), it is
  implementation-defined whether the result of the %Z and %z strftime() and
  wcsftime() conversion specifiers shall refer to UTC or the current local
  time zone, when strftime() or wcsftime() is called with such a broken-down
  time structure.

I think it's too late to get this restriction into the Austin Group revised
POSIX spec, but some version of it probably ought to go into the tzcode man
pages (along with documentation of what tzcode does for the second case,
which is dependent on the value of TM_ZONE and TM_GMTOFF at compile-time).


The motivating example for the first two paragraphs is the code attached
below (test-tzchange.c). It produces the following output on FreeBSD 4.3
(which uses a slightly old version of tzcode, with some local changes that
shouldn't affect this; it defines TM_ZONE and TM_GMTOFF):

$ ./test-tzchange 
Fri 04 May 11:11:00 2001 EDT
Fri 04 May 11:11:00 2001 PPT
Fri 04 May 11:11:00 2001 PDT

This occurs because lclptr->chars has a different value for the two time
zones; since test_tm->tm_zone is a pointer into lclptr->chars, it ends up
pointing somewhere bogus, and thus claiming that "Pacific Peace Time" was
used in 2001.

I don't think it's possible to fix this in tzcode without either breaking
binary compatibility of 'struct tm', leaking memory on a TZ change, or
breaking %Z for non-current time zones.


The motivating example for the third paragraph is that System V (at least
Solaris) and tzcode do different things, and I don't think either one is
about to change.  (System V always gets its %Z from tzname[i], I think.)


The underlying motivation for all this is that I don't see any sensible way
to set tm_zone, for struct tm's produced by reentrant timezone functions,
that doesn't end up leading to free pointer dereferences following
tz_free().  However, if the analogous operation for process-wide timezones
is *already* undefined, it's clearly not nearly as much of a problem.


What do people think about this?

-------------- next part --------------
An embedded and charset-unspecified text was scrubbed...
Name: test-tzchange.c
Url: http://mm.icann.org/pipermail/tz/attachments/20010611/a05b9581/test-tzchange-0001.c 
-------------- next part --------------

-- 
Jonathan Lennox
lennox at cs.columbia.edu


More information about the tz mailing list