Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

localtime(3) calls tzset(3), but localtime_r(3) may not. #7092

Closed
p5pRT opened this issue Feb 7, 2004 · 35 comments
Closed

localtime(3) calls tzset(3), but localtime_r(3) may not. #7092

p5pRT opened this issue Feb 7, 2004 · 35 comments

Comments

@p5pRT
Copy link

p5pRT commented Feb 7, 2004

Migrated from rt.perl.org#26136 (status was 'resolved')

Searchable as RT26136$

@p5pRT
Copy link
Author

p5pRT commented Feb 7, 2004

From sagawa@sohgoh.net

This is a bug report for perl from sagawa@​sohgoh.net,
generated with the help of perlbug 1.34 running under perl v5.8.2.

I use cygwin perl package (5.8.2-1) and localtime returns gmtime
as same as #24582.
( http​://rt.perl.org/rt3/Ticket/Display.html?id=24582 ).
I noticed that Cygwin 5.8.2-1 package supports thread,
but 5.8.0-5 doesn't, and threaded perl calls localtime_r(3)
instead of localtime(3) as far as my reading.

In cygwin environment (and some other libc),
localtime(3) calls tzset(3), but localtime_r(3) does not.
I should write a patch that calls tzset(3) before localtime_r(3) under
ordinary circumstances, but I'm not familiar to perl sorce code,
thus I show this situation in short C.

#include <stdio.h>
#include <time.h>

int main(int argc, char *argv[]) {
  time_t t;
  struct tm lctime;

  t = time(NULL);
  printf("time_t​: %d\n", t);
  localtime_r(&t, &lctime);
  printf("Local​: %s", asctime(&lctime));
  gmtime_r(&t, &lctime);
  printf(" GMT : %s", asctime(&lctime));

  printf("call tzset\n");
  tzset();
  localtime_r(&t, &lctime);
  printf("Local​: %s", asctime(&lctime));
  gmtime_r(&t, &lctime);
  printf(" GMT : %s", asctime(&lctime));

  exit(0);
}

Local timezone is JST​:GMT+09, and this short program shows​:

Local​: Sat Feb 7 13​:47​:25 2004 (wrong -- GMT)
GMT : Sat Feb 7 13​:47​:25 2004
call tzset
Local​: Sat Feb 7 22​:47​:25 2004 (ok :)
GMT : Sat Feb 7 13​:47​:25 2004


Flags​:
  category=core
  severity=medium


Site configuration information for perl v5.8.2​:

Configured by Gerrit at Fri Nov 7 12​:03​:56 2003.

Summary of my perl5 (revision 5.0 version 8 subversion 2) configuration​:
  Platform​:
  osname=cygwin, osvers=1.5.5(0.9432), archname=cygwin-thread-multi-64int
  uname='cygwin_nt-5.0 troubardix 1.5.5(0.9432) 2003-09-20 16​:31 i686 unknown unknown cygwin '
  config_args='-de -Dmksymlinks -Duse64bitint -Dusethreads -Doptimize=-O2 -Dman3ext=3pm'
  hint=recommended, useposix=true, d_sigaction=define
  usethreads=define use5005threads=undef useithreads=define usemultiplicity=define
  useperlio=define d_sfio=undef uselargefiles=define usesocks=undef
  use64bitint=define use64bitall=undef uselongdouble=undef
  usemymalloc=y, bincompat5005=undef
  Compiler​:
  cc='gcc', ccflags ='-DPERL_USE_SAFE_PUTENV -fno-strict-aliasing',
  optimize='-O2',
  cppflags='-DPERL_USE_SAFE_PUTENV -fno-strict-aliasing'
  ccversion='', gccversion='3.3.1 (cygming special)', gccosandvers=''
  intsize=4, longsize=4, ptrsize=4, doublesize=8, byteorder=12345678
  d_longlong=define, longlongsize=8, d_longdbl=define, longdblsize=12
  ivtype='long long', ivsize=8, nvtype='double', nvsize=8, Off_t='off_t', lseeksize=8
  alignbytes=8, prototype=define
  Linker and Libraries​:
  ld='ld2', ldflags =' -s -L/usr/local/lib'
  libpth=/usr/local/lib /usr/lib /lib
  libs=-lgdbm -ldb -lcrypt -lgdbm_compat
  perllibs=-lcrypt -lgdbm_compat
  libc=/usr/lib/libc.a, so=dll, useshrplib=true, libperl=libperl.a
  gnulibc_version=''
  Dynamic Linking​:
  dlsrc=dl_dlopen.xs, dlext=dll, d_dlsymun=undef, ccdlflags=' -s'
  cccdlflags=' ', lddlflags=' -s -L/usr/local/lib'

Locally applied patches​:
 


@​INC for perl v5.8.2​:
  /usr/lib/perl5/5.8.2/cygwin-thread-multi-64int
  /usr/lib/perl5/5.8.2
  /usr/lib/perl5/site_perl/5.8.2/cygwin-thread-multi-64int
  /usr/lib/perl5/site_perl/5.8.2
  /usr/lib/perl5/site_perl
  .


Environment for perl v5.8.2​:
  CYGWIN_HOME=D​:\home\sagawa
  HOME=/home/sagawa
  LANG=ja_JP.eucJP
  LANGUAGE (unset)
  LD_LIBRARY_PATH (unset)
  LOGDIR (unset)
  PATH=/home/sagawa/bin​:/usr/local/bin​:/usr/bin​:/usr/X11R6/bin​:/usr/local/tex/bin​:/usr/local/bin​:/usr/bin​:/bin​:/usr/sbin​:/sbin​:/usr/local/bin​:/usr/bin​:/bin​:/cygdrive/c/WINDOWS/system32​:/cygdrive/c/WINDOWS​:/cygdrive/c/WINDOWS/System32/Wbem​:/usr/X11R6/bin
  PERLDOC_PAGER=less -R
  PERL_BADLANG (unset)
  SHELL=/bin/zsh

--
Akihiro SAGAWA <sagawa@​sohgoh.net>

@p5pRT
Copy link
Author

p5pRT commented Feb 8, 2004

From @ysth

On Sat, Feb 07, 2004 at 01​:49​:23PM -0000, "sagawa@​sohgoh.net (via RT)" <perlbug-followup@​perl.org> wrote​:

I use cygwin perl package (5.8.2-1) and localtime returns gmtime
as same as #24582.
( http​://rt.perl.org/rt3/Ticket/Display.html?id=24582 ).
I noticed that Cygwin 5.8.2-1 package supports thread,
but 5.8.0-5 doesn't, and threaded perl calls localtime_r(3)
instead of localtime(3) as far as my reading.

Thank you so much for tracking this down.

In cygwin environment (and some other libc),
localtime(3) calls tzset(3), but localtime_r(3) does not.

I'm not sure if this is a perl bug or cygwin/newlib bug.
I've asked on the cygwin list​:

http​://cygwin.com/ml/cygwin/2004-02/msg00346.html

As a temporary workaround, a tzset() call during startup might be a
good idea.

@p5pRT
Copy link
Author

p5pRT commented Feb 8, 2004

The RT System itself - Status changed from 'new' to 'open'

@p5pRT
Copy link
Author

p5pRT commented Feb 11, 2004

From gp@familiehaase.de

Hallo Akihiro,

many thanks for this excellent bug report, I'll see how to integrate
this in the Perl source or if needed in the Cygwin sources as soon as
possible and release a new Perl package for Cygwin.

Gerrit

Am Samstag, 7. Februar 2004 um 14​:48 schriebst du​:

This is a bug report for perl from sagawa@​sohgoh.net,
generated with the help of perlbug 1.34 running under perl v5.8.2.

I use cygwin perl package (5.8.2-1) and localtime returns gmtime
as same as #24582.
( http​://rt.perl.org/rt3/Ticket/Display.html?id=24582 ).
I noticed that Cygwin 5.8.2-1 package supports thread,
but 5.8.0-5 doesn't, and threaded perl calls localtime_r(3)
instead of localtime(3) as far as my reading.

In cygwin environment (and some other libc),
localtime(3) calls tzset(3), but localtime_r(3) does not.
I should write a patch that calls tzset(3) before localtime_r(3) under
ordinary circumstances, but I'm not familiar to perl sorce code,
thus I show this situation in short C.

#include <stdio.h>
#include <time.h>

int main(int argc, char *argv[]) {
time_t t;
struct tm lctime;

t = time\(NULL\);
printf\("time\_t&#8203;: %d\\n"\, t\);
localtime\_r\(&t\, &lctime\);
printf\("Local&#8203;: %s"\, asctime\(&lctime\)\);
gmtime\_r\(&t\, &lctime\);
printf\(" GMT : %s"\, asctime\(&lctime\)\);
printf\("call tzset\\n"\);
tzset\(\);
localtime\_r\(&t\, &lctime\);
printf\("Local&#8203;: %s"\, asctime\(&lctime\)\);
gmtime\_r\(&t\, &lctime\);
printf\(" GMT : %s"\, asctime\(&lctime\)\);
exit\(0\);

}

Local timezone is JST​:GMT+09, and this short program shows​:

Local​: Sat Feb 7 13​:47​:25 2004 (wrong -- GMT)
GMT : Sat Feb 7 13​:47​:25 2004
call tzset
Local​: Sat Feb 7 22​:47​:25 2004 (ok :)
GMT : Sat Feb 7 13​:47​:25 2004

---
Flags​:
category=core
severity=medium
---
Site configuration information for perl v5.8.2​:

Configured by Gerrit at Fri Nov 7 12​:03​:56 2003.

Summary of my perl5 (revision 5.0 version 8 subversion 2) configuration​:
Platform​:
osname=cygwin, osvers=1.5.5(0.9432),
archname=cygwin-thread-multi-64int
uname='cygwin_nt-5.0 troubardix 1.5.5(0.9432) 2003-09-20
16​:31 i686 unknown unknown cygwin '
config_args='-de -Dmksymlinks -Duse64bitint -Dusethreads -Doptimize=-O2 -Dman3ext=3pm'
hint=recommended, useposix=true, d_sigaction=define
usethreads=define use5005threads=undef useithreads=define usemultiplicity=define
useperlio=define d_sfio=undef uselargefiles=define usesocks=undef
use64bitint=define use64bitall=undef uselongdouble=undef
usemymalloc=y, bincompat5005=undef
Compiler​:
cc='gcc', ccflags ='-DPERL_USE_SAFE_PUTENV -fno-strict-aliasing',
optimize='-O2',
cppflags='-DPERL_USE_SAFE_PUTENV -fno-strict-aliasing'
ccversion='', gccversion='3.3.1 (cygming special)', gccosandvers=''
intsize=4, longsize=4, ptrsize=4, doublesize=8, byteorder=12345678
d_longlong=define, longlongsize=8, d_longdbl=define, longdblsize=12
ivtype='long long', ivsize=8, nvtype='double', nvsize=8, Off_t='off_t', lseeksize=8
alignbytes=8, prototype=define
Linker and Libraries​:
ld='ld2', ldflags =' -s -L/usr/local/lib'
libpth=/usr/local/lib /usr/lib /lib
libs=-lgdbm -ldb -lcrypt -lgdbm_compat
perllibs=-lcrypt -lgdbm_compat
libc=/usr/lib/libc.a, so=dll, useshrplib=true, libperl=libperl.a
gnulibc_version=''
Dynamic Linking​:
dlsrc=dl_dlopen.xs, dlext=dll, d_dlsymun=undef, ccdlflags=' -s'
cccdlflags=' ', lddlflags=' -s -L/usr/local/lib'

Locally applied patches​:
 

---
@​INC for perl v5.8.2​:
/usr/lib/perl5/5.8.2/cygwin-thread-multi-64int
/usr/lib/perl5/5.8.2
/usr/lib/perl5/site_perl/5.8.2/cygwin-thread-multi-64int
/usr/lib/perl5/site_perl/5.8.2
/usr/lib/perl5/site_perl
.

---
Environment for perl v5.8.2​:
CYGWIN_HOME=D​:\home\sagawa
HOME=/home/sagawa
LANG=ja_JP.eucJP
LANGUAGE (unset)
LD_LIBRARY_PATH (unset)
LOGDIR (unset)

PATH=/home/sagawa/bin​:/usr/local/bin​:/usr/bin​:/usr/X11R6/bin​:/usr/local/tex/bin​:/usr/local/bin​:/usr/bin​:/bin​:/usr/sbin​:/sbin​:/usr/local/bin​:/usr/bin​:/bin​:/cygdrive/c/WINDOWS/system32​:/cygdrive/c/WINDOWS​:/cygdrive/c/WINDOWS/System32/Wbem​:/usr/X11R6/bin
PERLDOC_PAGER=less -R
PERL_BADLANG (unset)
SHELL=/bin/zsh

--
=^..^=

@p5pRT
Copy link
Author

p5pRT commented Feb 14, 2004

From sagawa@sohgoh.net

In "Re​: [perl #26136] localtime(3) calls tzset(3), but localtime_r(3)
may not.", "Yitzchak Scott-Thoennes via RT" wrote​:

In cygwin environment (and some other libc),
localtime(3) calls tzset(3), but localtime_r(3) does not.

I'm not sure if this is a perl bug or cygwin/newlib bug.
I've asked on the cygwin list​:

http​://cygwin.com/ml/cygwin/2004-02/msg00346.html
And now, thanks to Christopher Faylor and Yitzchak Scott-Thoennes,
Cygwin's localtime_r(3) calls tzset(3) internally. Thank you! :)
# http​://cygwin.com/ml/cygwin/2004-02/msg00576.html

By the way, I found the same problem on NetBSD's localtime_r(3), and
this reported as PR #10282. They said this is not a bug.
http​://www.netbsd.org/cgi-bin/query-pr-single.pl?number=10282

And glibc has a problem when we redefine TZ environment variable.​:(

Please check this C and its result.

#include <stdio.h>
#include <time.h>

int main(int argc, char *argv[])
{
  time_t t;
  struct tm lctime;

  t = time(NULL);
  printf("time_t​: %d\n", t);
  localtime_r(&t, &lctime);
  printf("Local​: %s", asctime(&lctime));
  gmtime_r(&t, &lctime);
  printf(" GMT : %s", asctime(&lctime));

  printf("call tzset\n");
  tzset();

  localtime_r(&t, &lctime);
  printf("Local​: %s", asctime(&lctime));
  gmtime_r(&t, &lctime);
  printf(" GMT : %s", asctime(&lctime));

  printf("redefine timezone\n");
  putenv("TZ=GMT+3");

  localtime_r(&t, &lctime);
  printf("Local​: %s", asctime(&lctime));
  gmtime_r(&t, &lctime);
  printf(" GMT : %s", asctime(&lctime));

  printf("call tzset\n");
  tzset();

  localtime_r(&t, &lctime);
  printf("Local​: %s", asctime(&lctime));
  gmtime_r(&t, &lctime);
  printf(" GMT : %s", asctime(&lctime));

  exit(0);
}

[ FreeBSD 5.2, SunOS 5.8 (+ Cygwin snapshot?)]
time_t​: 1076767315
Local​: Sat Feb 14 23​:01​:55 2004 (JST=GMT+9, ok)
GMT : Sat Feb 14 14​:01​:55 2004
call tzset
Local​: Sat Feb 14 23​:01​:55 2004 (ok)
GMT : Sat Feb 14 14​:01​:55 2004
redefine timezone
Local​: Sat Feb 14 11​:01​:55 2004 (yes, GMT+3)
GMT : Sat Feb 14 14​:01​:55 2004
call tzset
Local​: Sat Feb 14 11​:01​:55 2004 (ok)
GMT : Sat Feb 14 14​:01​:55 2004

[ Linux glibc 2.2.5, 2.1.3 ]
time_t​: 1076767340
Local​: Sat Feb 14 23​:02​:20 2004 (JST=GMT+9, ok)
GMT : Sat Feb 14 14​:02​:20 2004
call tzset
Local​: Sat Feb 14 23​:02​:20 2004 (JST=GMT+9, ok)
GMT : Sat Feb 14 14​:02​:20 2004
redefine timezone
Local​: Sat Feb 14 23​:02​:20 2004 (not GMT+3, still JST)
GMT : Sat Feb 14 14​:02​:20 2004
call tzset
Local​: Sat Feb 14 17​:02​:20 2004 (ok GMT+3)
GMT : Sat Feb 14 14​:02​:20 2004

[ Cygwin 1.5.7, NetBSD 1.6ZH ]
time_t​: 1076767301
Local​: Sat Feb 14 14​:01​:41 2004 (JST=GMT+9, NG)
GMT : Sat Feb 14 14​:01​:41 2004
call tzset
Local​: Sat Feb 14 23​:01​:41 2004 (JST=GMT+9, ok)
GMT : Sat Feb 14 14​:01​:41 2004
redefine timezone
Local​: Sat Feb 14 23​:01​:41 2004 (not GMT+3)
GMT : Sat Feb 14 14​:01​:41 2004
call tzset
Local​: Sat Feb 14 17​:01​:41 2004 (ok GMT+3)
GMT : Sat Feb 14 14​:01​:41 2004

--
Akihiro SAGAWA <sagawa@​sohgoh.net>

@p5pRT
Copy link
Author

p5pRT commented Feb 15, 2004

From @ysth

On Sun, Feb 15, 2004 at 12​:12​:39AM +0900, Akihiro Sagawa <sagawa@​sohgoh.net> wrote​:

In "Re​: [perl #26136] localtime(3) calls tzset(3), but localtime_r(3)
may not.", "Yitzchak Scott-Thoennes via RT" wrote​:

In cygwin environment (and some other libc),
localtime(3) calls tzset(3), but localtime_r(3) does not.

I'm not sure if this is a perl bug or cygwin/newlib bug.
I've asked on the cygwin list​:

http​://cygwin.com/ml/cygwin/2004-02/msg00346.html
And now, thanks to Christopher Faylor and Yitzchak Scott-Thoennes,
Cygwin's localtime_r(3) calls tzset(3) internally. Thank you! :)
# http​://cygwin.com/ml/cygwin/2004-02/msg00576.html

All CGF's fault, I didn't do anything.

By the way, I found the same problem on NetBSD's localtime_r(3), and
this reported as PR #10282. They said this is not a bug.
http​://www.netbsd.org/cgi-bin/query-pr-single.pl?number=10282

As I said on the cygwin list, the following bits of susv3 lead me to
conclude that localtime_r should return a time *as if tzset had been
called*, though actually setting the globals it would have set isn't
required​:

  "Local timezone information is used as though localtime() calls tzset().

  The relationship between a time in seconds since the Epoch used as
  an argument to localtime() and the tm structure (defined in the
  <time.h> header) is that the result shall be...corrected for timezone
  and any seasonal time adjustments...

  The same relationship shall apply for localtime_r().
  ...
  Unlike localtime(), the reentrant version is not required to set
  tzname.

But it seems as if this isn't clear enough to be the practice. Would
it be good for perl's Configure to compare the results of localtime and
localtime_r and decide if we need an extra tzset? Are there thread-
unsafety possibilities in calling tzset?

@p5pRT
Copy link
Author

p5pRT commented Feb 25, 2004

From sagawa@sohgoh.net

In "Re​: [perl #26136] localtime(3) calls tzset(3), but localtime_r(3)
may not.", "Yitzchak Scott-Thoennes" wrote​:

But it seems as if this isn't clear enough to be the practice. Would
it be good for perl's Configure to compare the results of localtime and
localtime_r and decide if we need an extra tzset? Are there thread-
unsafety possibilities in calling tzset?

It is good idea that perl's Configure checks localtime_r behavior.
We should always set tzname[].

Tzset() and localtime_r() might be separated between threads.
At least FreeBSD, tzset_basic and localsub are enclosed in a mutex lock.
Otherwise following situation occurs.
  Thread1 Therad2
  tzset()
  tzset()
  localtime()
  localtime()

--
Akihiro SAGAWA <sagawa@​sohgoh.net>

@p5pRT
Copy link
Author

p5pRT commented Feb 25, 2004

From @ysth

On Thu, Feb 26, 2004 at 12​:37​:06AM +0900, Akihiro Sagawa <sagawa@​sohgoh.net> wrote​:

In "Re​: [perl #26136] localtime(3) calls tzset(3), but localtime_r(3)
may not.", "Yitzchak Scott-Thoennes" wrote​:

But it seems as if this isn't clear enough to be the practice. Would
it be good for perl's Configure to compare the results of localtime and
localtime_r and decide if we need an extra tzset? Are there thread-
unsafety possibilities in calling tzset?

It is good idea that perl's Configure checks localtime_r behavior.
We should always set tzname[].

Tzset() and localtime_r() might be separated between threads.
At least FreeBSD, tzset_basic and localsub are enclosed in a mutex lock.
Otherwise following situation occurs.
Thread1 Therad2
tzset()
tzset()
localtime()
localtime()

localtime_r definitely isn't required to set the global tzname, etc.
What OS vendors ought to be doing is have localtime_r call a
tzset-like function that uses thread-local storage or just returns the
needed info. I don't see how we can solve this in perl without *some*
possibility of problems.

@p5pRT
Copy link
Author

p5pRT commented Sep 13, 2004

From wia@iglass.net

Created by wia@iglass.net

There seems to be a problem when changing the time zone and using
POSIX​::strftime to get the date. When the TZ is changed, the first
call to strftime shows the hour in the old TZ, but then subsequent calls
to strftime are correct.

It seems to work correct with perl RH 7.3 and perl 5.6.1 but found it to be
broken on RH Enterprise (U1, U2, & U3) and perl 5.8.0 Then tried perl 5.8.5
and 5.9.1 on RH 7.3 and that did not work either.

I had originally noticed the problem using Date-Handler.

Below is a sample script with output​:

-- start script
#!/usr/local/bin/perl

use POSIX qw(floor strftime mktime setlocale);

$ENV{'TZ'} = "US/Eastern";
$ENV{'LC_TIME'} = 'en_US';

my $TZ1 = "US/Central";
my $TZ2 = "US/Eastern";

{
  local $ENV{'TZ'} = $TZ1;
  local $ENV{'LC_TIME'} = 'en_US';
  $Date1 = strftime("%c", localtime($^T));
  print "DATE1 = $Date1\n";
  $Date2 = strftime("%c", localtime($^T));
  print "DATE2 = $Date2\n";
  $Date3 = strftime("%c", localtime($^T));
  print "DATE3 = $Date3\n";
  print "\n";
}

{
  local $ENV{'TZ'} = $TZ2;
  local $ENV{'LC_TIME'} = 'en_US';
  $Date4 = strftime("%c", localtime($^T));
  print "DATE4 = $Date4\n";
  $Date5 = strftime("%c", localtime($^T));
  print "DATE5 = $Date5\n";
  $Date6 = strftime("%c", localtime($^T));
  print "DATE6 = $Date6\n";
  print "\n";
}

{
  local $ENV{'TZ'} = $TZ1;
  local $ENV{'LC_TIME'} = 'en_US';
  $Date7 = strftime("%c", localtime($^T));
  print "DATE7 = $Date7\n";
  $Date8 = strftime("%c", localtime($^T));
  print "DATE8 = $Date8\n";
  $Date9 = strftime("%c", localtime($^T));
  print "DATE9 = $Date9\n";
  print "\n";
}
-- end script

-- start output
DATE1 = Mon 13 Sep 2004 09​:59​:44 AM CDT
DATE2 = Mon 13 Sep 2004 09​:59​:44 AM CDT
DATE3 = Mon 13 Sep 2004 09​:59​:44 AM CDT

DATE4 = Mon 13 Sep 2004 09​:59​:44 AM EDT
DATE5 = Mon 13 Sep 2004 10​:59​:44 AM EDT
DATE6 = Mon 13 Sep 2004 10​:59​:44 AM EDT

DATE7 = Mon 13 Sep 2004 10​:59​:44 AM CDT
DATE8 = Mon 13 Sep 2004 09​:59​:44 AM CDT
DATE9 = Mon 13 Sep 2004 09​:59​:44 AM CDT
-- end output

thanks,
marc

Perl Info

Flags:
    category=library
    severity=high

Site configuration information for perl v5.8.0:

Configured by bhcompile'
cf_email='bhcompile at Mon Sep 15 10:01:56 EDT 2003.

Summary of my rderl (revision 5.0 version 8 subversion 0) configuration:
  Platform:
    osname=linux, osvers=2.4.21-1.1931.2.393.entsmp, archname=i386-linux-thread-multi
    uname='linux por'
    config_args='-des -Doptimize=-O2 -g -pipe -march=i386 -mcpu=i686 -Dmyhostname=localhost -Dperladmin=root@localhost -Dcc=gcc -Dcf_by=Red Hat, Inc. -Dinstallprefix=/usr -Dprefix=/usr -Darchname=i386-linux -Dvendorprefix=/usr -Dsiteprefix=/usr -Dotherlibdirs=/usr/lib/perl5/5.8.0 -Duseshrplib -Dusethreads -Duseithreads -Duselargefiles -Dd_dosuid -Dd_semctl_semun -Di_db -Ui_ndbm -Di_gdbm -Di_shadow -Di_syslog -Dman3ext=3pm -Duseperlio -Dinstallusrbinperl -Ubincompat5005 -Uversiononly -Dpager=/usr/bin/less -isr'
    hint=recommended, useposix=true, d_sigaction=define
    usethreads=define use5005threads=undef'
 useithreads=define usemultiplicity=
    useperlio= d_sfio=undef uselargefiles=define usesocks=undef
    use64bitint=undef use64bitall=un uselongdouble=
    usemymalloc=, bincompat5005=undef
  Compiler:
    cc='gcc', ccflags ='-D_REENTRANT -D_GNU_SOURCE -DTHREADS_HAVE_PIDS -DDEBUGGING -fno-strict-aliasing -I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -I/usr/include/gdbm',
    optimize='',
    cppflags='-D_REENTRANT -D_GNU_SOURCE -DTHREADS_HAVE_PIDS -DDEBUGGING -fno-strict-aliasing -I/usr/local/include -I/usr/include/gdbm'
    ccversion='', gccversion='3.2.3 20030502 (Red Hat Linux 3.2.3-19)', gccosandvers=''
gccversion='3.2.3 200305'
    intsize=o, longsize=s, ptrsize=l, doublesize=8, byteorder=1234
    d_longlong=define, longlongsize=8, d_longdbl=define, longdblsize=12
    ivtype='long'
k', ivsize=4'
ivtype, nvtype='double'
o_no', nvsize=, Off_t='', lseeksize=8
    alignbytes=4, prototype=define
  Linker and Libraries:
    ld='gcc'
l', ldflags =' -L/usr/local/lib'
ldflags_use'
    libpth=/usr/local/lib /lib /usr/lib
    libs=-lnsl -lgdbm -ldb -ldl -lm -lpthread -lc -lcrypt -lutil
    perllibs=
    libc=/lib/libc-2.3.2.so, so=so, useshrplib=true, libperl=libper
    gnulibc_version='2.3.2'
  Dynamic Linking:
    dlsrc=dl_dlopen.xs, dlext=so', d_dlsymun=undef, ccdlflags='-rdynamic -Wl,-rpath,/usr/lib/perl5/5.8.0/i386-linux-thread-multi/CORE'
    cccdlflags='-fPIC'
ccdlflags='-rdynamic -Wl,-rpath,/usr/lib/perl5', lddlflags='s Unicode/Normalize XS/A'

Locally applied patches:
    MAINT18379


@INC for perl v5.8.0:
    /usr/lib/perl5/5.8.0/i386-linux-thread-multi
    /usr/lib/perl5/5.8.0
    /usr/lib/perl5/site_perl/5.8.0/i386-linux-thread-multi
    /usr/lib/perl5/site_perl/5.8.0
    /usr/lib/perl5/site_perl
    /usr/lib/perl5/vendor_perl/5.8.0/i386-linux-thread-multi
    /usr/lib/perl5/vendor_perl/5.8.0
    /usr/lib/perl5/vendor_perl
    /usr/lib/perl5/5.8.0/i386-linux-thread-multi
    /usr/lib/perl5/5.8.0
    .


Environment for perl v5.8.0:
    HOME=/home/noc
    LANG=en_US.UTF-8
    LANGUAGE (unset)
    LD_LIBRARY_PATH=/usr/lib:/usr/local/lib:/usr/openwin/lib
    LOGDIR (unset)
    PATH=/bin:/usr/sbin:/sbin:/usr/bin:/usr/local/bin:/usr/X11R6/bin:/home/noc/bin:/home/iglass/bin:/usr/local/rrdtool-1.0.41/bin:/home/noc/bin:/opt/OpenNMS:/opt/OpenNMS/bin:/home/unix/cricket/cricket
    PERL_BADLANG (unset)
    SHELL=/bin/bash
    dlflags='-share (unset)

@p5pRT
Copy link
Author

p5pRT commented Sep 13, 2004

From @smpeters

From what I understand, the output should look like​:

steve@​kirk sandbox $ perl tz.pl
DATE1 = Mon Sep 13 18​:48​:10 2004
DATE2 = Mon Sep 13 18​:48​:10 2004
DATE3 = Mon Sep 13 18​:48​:10 2004

DATE4 = Mon Sep 13 19​:48​:10 2004
DATE5 = Mon Sep 13 19​:48​:10 2004
DATE6 = Mon Sep 13 19​:48​:10 2004

DATE7 = Mon Sep 13 18​:48​:10 2004
DATE8 = Mon Sep 13 18​:48​:10 2004
DATE9 = Mon Sep 13 18​:48​:10 2004

If so, I had it work just fine on Perl 5.8.5 on Gentoo Linux 2.4.26 and
with Perl 5.8.2 on Mac OS X 10.2.

My guess is that there is something hateful occuring in glibc or
elsewhere in the GNU tool chain that is causing this problem.

Steve Peters
steve@​fisharerojo.org

@p5pRT
Copy link
Author

p5pRT commented Sep 13, 2004

@smpeters - Status changed from 'new' to 'open'

@p5pRT
Copy link
Author

p5pRT commented Sep 14, 2004

From wia@iglass.net

[stmpeters - Mon Sep 13 16​:53​:53 2004]​:

From what I understand, the output should look like​:

steve@​kirk sandbox $ perl tz.pl
DATE1 = Mon Sep 13 18​:48​:10 2004
DATE2 = Mon Sep 13 18​:48​:10 2004
DATE3 = Mon Sep 13 18​:48​:10 2004

DATE4 = Mon Sep 13 19​:48​:10 2004
DATE5 = Mon Sep 13 19​:48​:10 2004
DATE6 = Mon Sep 13 19​:48​:10 2004

DATE7 = Mon Sep 13 18​:48​:10 2004
DATE8 = Mon Sep 13 18​:48​:10 2004
DATE9 = Mon Sep 13 18​:48​:10 2004

If so, I had it work just fine on Perl 5.8.5 on Gentoo Linux 2.4.26 and
with Perl 5.8.2 on Mac OS X 10.2.

My guess is that there is something hateful occuring in glibc or
elsewhere in the GNU tool chain that is causing this problem.

Steve Peters
steve@​fisharerojo.org

Yes, that is what the output should look like. And thats what I get
with RedHat 7.3 and perl 5.6.1, but on the same RH 7.3 machine with
perl 5.8.5 I see the problem. Should be the same glibc?

marc

@p5pRT
Copy link
Author

p5pRT commented Sep 14, 2004

From @iabyn

On Mon, Sep 13, 2004 at 11​:53​:53PM -0000, Steve Peters via RT wrote​:

From what I understand, the output should look like​:

steve@​kirk sandbox $ perl tz.pl
DATE1 = Mon Sep 13 18​:48​:10 2004
DATE2 = Mon Sep 13 18​:48​:10 2004
DATE3 = Mon Sep 13 18​:48​:10 2004

DATE4 = Mon Sep 13 19​:48​:10 2004
DATE5 = Mon Sep 13 19​:48​:10 2004
DATE6 = Mon Sep 13 19​:48​:10 2004

DATE7 = Mon Sep 13 18​:48​:10 2004
DATE8 = Mon Sep 13 18​:48​:10 2004
DATE9 = Mon Sep 13 18​:48​:10 2004

If so, I had it work just fine on Perl 5.8.5 on Gentoo Linux 2.4.26 and
with Perl 5.8.2 on Mac OS X 10.2.

My guess is that there is something hateful occuring in glibc or
elsewhere in the GNU tool chain that is causing this problem.

It appears to be a problem with the timezone info returned by localtime
under threaded builds. I've tried it on RH7.2 and Fedora Core 2, and the
following test script failed on both​:

  $summertime = 1095201834;
  $ENV{'TZ'} = "GMT";
  print "not " if (localtime($summertime))[-1]; print "ok 1\n";
  $ENV{'TZ'} = "GB";
  print "not " if !(localtime($summertime))[-1]; print "ok 2\n";
  print "not " if !(localtime($summertime))[-1]; print "ok 3\n";

with TZ=GB, DST is supposed to be 1; on threaded builds I get

  ok 1
  not ok 2
  not ok 3

On Solaris it succeeds.

So it's proably a bug with the Linux localtime_r(3) libarary.

--
Red sky at night - gerroff my land!
Red sky at morning - gerroff my land!
  -- old farmers' sayings #14

@p5pRT
Copy link
Author

p5pRT commented Sep 15, 2004

From @ysth

On Tue, Sep 14, 2004 at 11​:57​:04PM +0100, Dave Mitchell <davem@​iabyn.com> wrote​:

So it's proably a bug with the Linux localtime_r(3) libarary.

A configure probe to manually do tzset before calling localtime_r
might be nice. IIRC, SUSv3 is somewhat confusing on this issue​:
localtime_r isn't required to call tzset, but is (reading closely, and
somewhat between the lines) required to return appropriate results *as
if it had been called*. cygwin used to get this wrong, too.

@p5pRT
Copy link
Author

p5pRT commented Nov 3, 2005

From jvdias@redhat.com

Greetings -

The fact that glibc's localtime_r does not call tzset()
causes problems to people using perl-5.8.x compiled for
threads, who may try to set the timezone with $ENV{TZ},
as shown by this test case​:


#!/usr/bin/perl
$t = time();
$ENV{'TZ'}="US/Eastern";
$east = scalar( localtime( $t ) );
$ENV{'TZ'}="US/Western";
$west = scalar( localtime( $t ) );
if ( $east eq $west )
{
  exit 1;
};


This program will exit with status 1 on all glibc using
multi-threaded perl-5.8.x builds.
Inserting a call to POSIX​::tzset at line 6 will make it return 0​:
... POSIX​::tzset(); $west = scalar( localtime( $t ) );

Contrary to speculation in bug #26136, this is not due
to a glibc bug - POSIX.1 8.3.7.2 says that localtime_r
is not required to call tzset. It would not be a good
idea for glibc's localtime_r to do so, as 'char tzname[]'
is not a thread specific variable, but a global glibc
variable. glibc's tzset() uses mutex locking to provide
thread exclusion in tzset() calls.

The last post to bug 26126 stated​:

CC​: Steve Peters via RT <bugs-perl5@​netlabs.develooper.com>,
"OtherRecipients of perl Ticket #31546"​: ;, perl5-porters@​perl.org Subject​:
Re​: [perl #31546] Changing TZ problem with POSIX strftime Date​: Wed, 15 Sep
2004 02​:28​:05 -0700
To​: Dave Mitchell <davem@​iabyn.com>
From​: Yitzchak Scott-Thoennes <sthoenna@​efn.org>

On Tue, Sep 14, 2004 at 11​:57​:04PM +0100, Dave Mitchell <davem@​iabyn.com> wrote​:

So it's proably a bug with the Linux localtime_r(3) libarary.

A configure probe to manually do tzset before calling localtime_r
might be nice. IIRC, SUSv3 is somewhat confusing on this issue​:
localtime_r isn't required to call tzset, but is (reading closely, and
somewhat between the lines) required to return appropriate results *as
if it had been called*. cygwin used to get this wrong, too.

So here's an attempt at
"A configure probe to manually do tzset before calling localtime_r" ,
as a patch against the perl-5.8.7 source .

The patch finds out if the libc's localtime_r calls tzset during Configure,
and if it does not, and the localtime_r REENTRANT_PROTO is being used, it
inserts a call to tzset before localtime_r in reentr.inc .

Please review this patch and let me know of any ideas / suggestions / comments
you may have about it, as I am considering applying it to the Red Hat perl
distribution to solve a number of Red Hat bugzillas on this issue.

Thanks & Regards,
Jason Vas Dias<jvdias@​redhat.com>
Red Hat perl package maintainer

___ BEGIN PATCH : gendiff perl-5.8.7 .orig :

Inline Patch
--- perl-5.8.7/reentr.inc.orig        2005-11-02 22:19:11.000000000 -0500
+++ perl-5.8.7/reentr.inc       2005-11-02 22:19:27.000000000 -0500
@@ -1368,10 +1368,10 @@
 #ifdef HAS_LOCALTIME_R
 #   undef localtime
 #   if !defined(localtime) && LOCALTIME_R_PROTO == REENTRANT_PROTO_S_TS
-#       define localtime(a) (localtime_r(a, &PL_reentrant_buffer->_localtime_struct) ? &PL_reentrant_buffer->_localtime_struct : 0)
+#       define localtime(a) ( L_R_TZSET localtime_r(a, &PL_reentrant_buffer->_localtime_struct) ? &PL_reentrant_buffer->_localtime_struct : 0)
 #   endif
 #   if !defined(localtime) && LOCALTIME_R_PROTO == REENTRANT_PROTO_I_TS
-#       define localtime(a) (localtime_r(a, &PL_reentrant_buffer->_localtime_struct) == 0 ? &PL_reentrant_buffer->_localtime_struct : 0)
+#       define localtime(a) ( L_R_TZSET localtime_r(a, &PL_reentrant_buffer->_localtime_struct) == 0 ? &PL_reentrant_buffer->_localtime_struct : 0)
 #   endif
 #endif /* HAS_LOCALTIME_R */

--- perl-5.8.7/config_h.SH.orig       2005-04-30 10:34:20.000000000 -0400
+++ perl-5.8.7/config_h.SH      2005-11-02 22:19:27.000000000 -0500
@@ -1916,7 +1916,18 @@
  */
 #$d_localtime_r HAS_LOCALTIME_R           /**/
 #define LOCALTIME_R_PROTO $localtime_r_proto      /**/
-
+/* LOCALTIME_R_NEEDS_TZSET :
+ *  many libc's localtime_r implementations do not call tzset,
+ *  making them differ from localtime(), and making timezone
+ *  changes using $ENV{TZ} without explicitly calling tzset
+ *  impossible. This symbol makes us call tzset before localtime_r:
+ */
+#$d_localtime_r_needs_tzset LOCALTIME_R_NEEDS_TZSET /**/
+#ifdef LOCALTIME_R_NEEDS_TZSET
+#define L_R_TZSET tzset(),
+#else
+#define L_R_TZSET
+#endif
 /* HAS_LONG_DOUBLE:
  *     This symbol will be defined if the C compiler supports long
  *     doubles.
--- perl-5.8.7/Configure.orig 2005-11-02 22:19:11.000000000 -0500
+++ perl-5.8.7/Configure        2005-11-02 22:19:41.000000000 -0500
@@ -528,6 +528,7 @@
 d_libm_lib_version=''
 d_link=''
 d_localtime_r=''
+d_localtime_r_needs_tzset=''
 localtime_r_proto=''
 d_locconv=''
 d_lockf=''
@@ -14023,7 +14024,51 @@
 *)     localtime_r_proto=0
        ;;
 esac
+: see if localtime_r calls tzset
+case "$localtime_r_proto" in
+REENTRANT_PROTO*)
+       $cat >try.c <<EOCP
+/*  Does our libc's localtime_r call tzset ?
+ *  return 0 if so, 1 otherwise.
+ */
+#include <sys/types.h>
+#include <unistd.h>
+#include <time.h>
+#include <string.h>
+#include <malloc.h>
+int main()
+{
+    time_t t = time(0L);
+    char w_tz[]="TZ=US/Eastern",
+        e_tz[]="TZ=US/Western",
+       *tz_e = (char*)malloc(16),
+       *tz_w = (char*)malloc(16);
+    struct tm tm_e, tm_w;
+
+    strcpy(tz_e,e_tz);
+    strcpy(tz_w,w_tz);
+
+    putenv(tz_e);
+    localtime_r(&t, &tm_e);
+
+    putenv(tz_w);
+    localtime_r(&t, &tm_w);

+    if( memcmp(&tm_e, &tm_w, sizeof(struct tm)) == 0 )
+       return 1;
+    return 0;
+}
+EOCP
+       set try
+       if eval $compile; then
+           if ./try; then
+               d_localtime_r_needs_tzset=undef;
+           else
+               d_localtime_r_needs_tzset=define;
+           fi;
+       fi;
+     ;;
+esac
 : see if localeconv exists
 set localeconv d_locconv
 eval $inlibc
@@ -20769,6 +20814,7 @@
 d_libm_lib_version='$d_libm_lib_version'
 d_link='$d_link'
 d_localtime_r='$d_localtime_r'
+d_localtime_r_needs_tzset='$d_localtime_r_needs_tzset'
 d_locconv='$d_locconv'
 d_lockf='$d_lockf'
 d_longdbl='$d_longdbl'
___ END PATCH

@p5pRT
Copy link
Author

p5pRT commented Nov 3, 2005

From @ysth

On Wed, Nov 02, 2005 at 10​:28​:41PM -0500, Jason Vas Dias wrote​:

Greetings -

The fact that glibc's localtime_r does not call tzset()
causes problems to people using perl-5.8.x compiled for
threads, who may try to set the timezone with $ENV{TZ},
as shown by this test case​:

---
#!/usr/bin/perl
$t = time();
$ENV{'TZ'}="US/Eastern";
$east = scalar( localtime( $t ) );
$ENV{'TZ'}="US/Western";
$west = scalar( localtime( $t ) );
if ( $east eq $west )
{
exit 1;
};
---

This program will exit with status 1 on all glibc using
multi-threaded perl-5.8.x builds.
Inserting a call to POSIX​::tzset at line 6 will make it return 0​:
... POSIX​::tzset(); $west = scalar( localtime( $t ) );

Contrary to speculation in bug #26136, this is not due
to a glibc bug - POSIX.1 8.3.7.2 says that localtime_r
is not required to call tzset.

Did you actually read the speculation you quote below? I say the
same​: it isn't required to call tzset. Actually, neither is
localtime(), but the latter *is* required to set the same global
variables as tzset, while localtime_r isn't required to set them.

localtime_r is however required to return a result "corrected for
timezone and any seasonal time adjustments", just as localtime is. If
you take that to mean timezone according to the last call (implicit or
explicit) to tzset(), glibc is in the clear. If you take that to mean
timezone according to $TZ, glibc is buggy. I think the latter makes a
whole lot more sense, since it says "The same relationship shall apply
for localtime_r()" as localtime(), and for localtime() it means
timezone as specified by $TZ.

(If you (RedHat) were able to approach the Open Group about clarifying
what SUSv3 requires, that might settle this once and for all, for all
platforms to see.)

It would not be a good
idea for glibc's localtime_r to do so, as 'char tzname[]'
is not a thread specific variable, but a global glibc
variable. glibc's tzset() uses mutex locking to provide
thread exclusion in tzset() calls.

So? What difference does that make? The point is whether the globals
get updated or not, localtime_r should (IMO) return a result based on
$TZ (which is also a global of a kind).

The last post to bug 26126 stated​:

CC​: Steve Peters via RT <bugs-perl5@​netlabs.develooper.com>,
"OtherRecipients of perl Ticket #31546"​: ;, perl5-porters@​perl.org Subject​:
Re​: [perl #31546] Changing TZ problem with POSIX strftime Date​: Wed, 15 Sep
2004 02​:28​:05 -0700
To​: Dave Mitchell <davem@​iabyn.com>
From​: Yitzchak Scott-Thoennes <sthoenna@​efn.org>

On Tue, Sep 14, 2004 at 11​:57​:04PM +0100, Dave Mitchell <davem@​iabyn.com> wrote​:

So it's proably a bug with the Linux localtime_r(3) libarary.

A configure probe to manually do tzset before calling localtime_r
might be nice. IIRC, SUSv3 is somewhat confusing on this issue​:
localtime_r isn't required to call tzset, but is (reading closely, and
somewhat between the lines) required to return appropriate results *as
if it had been called*. cygwin used to get this wrong, too.

So here's an attempt at
"A configure probe to manually do tzset before calling localtime_r" ,
as a patch against the perl-5.8.7 source .

Terrific!

The patch finds out if the libc's localtime_r calls tzset during Configure,
and if it does not, and the localtime_r REENTRANT_PROTO is being used, it
inserts a call to tzset before localtime_r in reentr.inc .

Please review this patch and let me know of any ideas / suggestions / comments
you may have about it, as I am considering applying it to the Red Hat perl
distribution to solve a number of Red Hat bugzillas on this issue.

Thanks & Regards,
Jason Vas Dias<jvdias@​redhat.com>
Red Hat perl package maintainer

___ BEGIN PATCH : gendiff perl-5.8.7 .orig :
--- perl-5.8.7/reentr.inc.orig 2005-11-02 22​:19​:11.000000000 -0500
+++ perl-5.8.7/reentr.inc 2005-11-02 22​:19​:27.000000000 -0500
@​@​ -1368,10 +1368,10 @​@​
#ifdef HAS_LOCALTIME_R
# undef localtime
# if !defined(localtime) && LOCALTIME_R_PROTO == REENTRANT_PROTO_S_TS
-# define localtime(a) (localtime_r(a, &PL_reentrant_buffer->_localtime_struct) ? &PL_reentrant_buffer->_localtime_struct : 0)
+# define localtime(a) ( L_R_TZSET localtime_r(a, &PL_reentrant_buffer->_localtime_struct) ? &PL_reentrant_buffer->_localtime_struct : 0)
# endif
# if !defined(localtime) && LOCALTIME_R_PROTO == REENTRANT_PROTO_I_TS
-# define localtime(a) (localtime_r(a, &PL_reentrant_buffer->_localtime_struct) == 0 ? &PL_reentrant_buffer->_localtime_struct : 0)
+# define localtime(a) ( L_R_TZSET localtime_r(a, &PL_reentrant_buffer->_localtime_struct) == 0 ? &PL_reentrant_buffer->_localtime_struct : 0)
# endif
#endif /* HAS_LOCALTIME_R */

--- perl-5.8.7/config_h.SH.orig 2005-04-30 10​:34​:20.000000000 -0400
+++ perl-5.8.7/config_h.SH 2005-11-02 22​:19​:27.000000000 -0500
@​@​ -1916,7 +1916,18 @​@​
*/
#$d_localtime_r HAS_LOCALTIME_R /**/
#define LOCALTIME_R_PROTO $localtime_r_proto /**/
-
+/* LOCALTIME_R_NEEDS_TZSET :
+ * many libc's localtime_r implementations do not call tzset,
+ * making them differ from localtime(), and making timezone
+ * changes using $ENV{TZ} without explicitly calling tzset
+ * impossible. This symbol makes us call tzset before localtime_r​:
+ */
+#$d_localtime_r_needs_tzset LOCALTIME_R_NEEDS_TZSET /**/
+#ifdef LOCALTIME_R_NEEDS_TZSET
+#define L_R_TZSET tzset(),
+#else
+#define L_R_TZSET
+#endif
/* HAS_LONG_DOUBLE​:
* This symbol will be defined if the C compiler supports long
* doubles.
--- perl-5.8.7/Configure.orig 2005-11-02 22​:19​:11.000000000 -0500
+++ perl-5.8.7/Configure 2005-11-02 22​:19​:41.000000000 -0500
@​@​ -528,6 +528,7 @​@​
d_libm_lib_version=''
d_link=''
d_localtime_r=''
+d_localtime_r_needs_tzset=''
localtime_r_proto=''
d_locconv=''
d_lockf=''
@​@​ -14023,7 +14024,51 @​@​
*) localtime_r_proto=0
;;
esac
+​: see if localtime_r calls tzset
+case "$localtime_r_proto" in
+REENTRANT_PROTO*)
+ $cat >try.c <<EOCP
+/* Does our libc's localtime_r call tzset ?
+ * return 0 if so, 1 otherwise.
+ */
+#include <sys/types.h>
+#include <unistd.h>
+#include <time.h>
+#include <string.h>
+#include <malloc.h>
+int main()
+{
+ time_t t = time(0L);
+ char w_tz[]="TZ=US/Eastern",
+ e_tz[]="TZ=US/Western",

Aren't those backwards?

Also, I would use non-Olson timezones, since they are by no means required.

So​: e_tz[]="TZ=EST5EDT"
and w_tz[]="TZ=PST8PDT"

+ *tz_e = (char*)malloc(16),
+ *tz_w = (char*)malloc(16);
+ struct tm tm_e, tm_w;
+
+ strcpy(tz_e,e_tz);
+ strcpy(tz_w,w_tz);
+
+ putenv(tz_e);
+ localtime_r(&t, &tm_e);
+
+ putenv(tz_w);
+ localtime_r(&t, &tm_w);

+ if( memcmp(&tm_e, &tm_w, sizeof(struct tm)) == 0 )
+ return 1;
+ return 0;
+}
+EOCP
+ set try
+ if eval $compile; then
+ if ./try; then
+ d_localtime_r_needs_tzset=undef;
+ else
+ d_localtime_r_needs_tzset=define;
+ fi;

If the compile failed, set it to undef?

+ fi;
+ ;;
+esac
: see if localeconv exists
set localeconv d_locconv
eval $inlibc
@​@​ -20769,6 +20814,7 @​@​
d_libm_lib_version='$d_libm_lib_version'
d_link='$d_link'
d_localtime_r='$d_localtime_r'
+d_localtime_r_needs_tzset='$d_localtime_r_needs_tzset'
d_locconv='$d_locconv'
d_lockf='$d_lockf'
d_longdbl='$d_longdbl'
___ END PATCH

@p5pRT
Copy link
Author

p5pRT commented Nov 3, 2005

From @ysth

Careful in responding to this; I just did so and cc'd perlbug inadvertently.

On Wed, Nov 02, 2005 at 10​:28​:41PM -0500, Jason Vas Dias wrote​:

Greetings -

The fact that glibc's localtime_r does not call tzset()
causes problems to people using perl-5.8.x compiled for
threads, who may try to set the timezone with $ENV{TZ},
as shown by this test case​:

---
#!/usr/bin/perl
$t = time();
$ENV{'TZ'}="US/Eastern";
$east = scalar( localtime( $t ) );
$ENV{'TZ'}="US/Western";
$west = scalar( localtime( $t ) );
if ( $east eq $west )
{
exit 1;
};
---

This program will exit with status 1 on all glibc using
multi-threaded perl-5.8.x builds.
Inserting a call to POSIX​::tzset at line 6 will make it return 0​:
... POSIX​::tzset(); $west = scalar( localtime( $t ) );

Contrary to speculation in bug #26136, this is not due
to a glibc bug - POSIX.1 8.3.7.2 says that localtime_r
is not required to call tzset. It would not be a good
idea for glibc's localtime_r to do so, as 'char tzname[]'
is not a thread specific variable, but a global glibc
variable. glibc's tzset() uses mutex locking to provide
thread exclusion in tzset() calls.

The last post to bug 26126 stated​:

CC​: Steve Peters via RT <bugs-perl5@​netlabs.develooper.com>,
"OtherRecipients of perl Ticket #31546"​: ;, perl5-porters@​perl.org Subject​:
Re​: [perl #31546] Changing TZ problem with POSIX strftime Date​: Wed, 15 Sep
2004 02​:28​:05 -0700
To​: Dave Mitchell <davem@​iabyn.com>
From​: Yitzchak Scott-Thoennes <sthoenna@​efn.org>

On Tue, Sep 14, 2004 at 11​:57​:04PM +0100, Dave Mitchell <davem@​iabyn.com> wrote​:

So it's proably a bug with the Linux localtime_r(3) libarary.

A configure probe to manually do tzset before calling localtime_r
might be nice. IIRC, SUSv3 is somewhat confusing on this issue​:
localtime_r isn't required to call tzset, but is (reading closely, and
somewhat between the lines) required to return appropriate results *as
if it had been called*. cygwin used to get this wrong, too.

So here's an attempt at
"A configure probe to manually do tzset before calling localtime_r" ,
as a patch against the perl-5.8.7 source .

The patch finds out if the libc's localtime_r calls tzset during Configure,
and if it does not, and the localtime_r REENTRANT_PROTO is being used, it
inserts a call to tzset before localtime_r in reentr.inc .

Please review this patch and let me know of any ideas / suggestions / comments
you may have about it, as I am considering applying it to the Red Hat perl
distribution to solve a number of Red Hat bugzillas on this issue.

Thanks & Regards,
Jason Vas Dias<jvdias@​redhat.com>
Red Hat perl package maintainer

___ BEGIN PATCH : gendiff perl-5.8.7 .orig :
--- perl-5.8.7/reentr.inc.orig 2005-11-02 22​:19​:11.000000000 -0500
+++ perl-5.8.7/reentr.inc 2005-11-02 22​:19​:27.000000000 -0500
@​@​ -1368,10 +1368,10 @​@​
#ifdef HAS_LOCALTIME_R
# undef localtime
# if !defined(localtime) && LOCALTIME_R_PROTO == REENTRANT_PROTO_S_TS
-# define localtime(a) (localtime_r(a, &PL_reentrant_buffer->_localtime_struct) ? &PL_reentrant_buffer->_localtime_struct : 0)
+# define localtime(a) ( L_R_TZSET localtime_r(a, &PL_reentrant_buffer->_localtime_struct) ? &PL_reentrant_buffer->_localtime_struct : 0)
# endif
# if !defined(localtime) && LOCALTIME_R_PROTO == REENTRANT_PROTO_I_TS
-# define localtime(a) (localtime_r(a, &PL_reentrant_buffer->_localtime_struct) == 0 ? &PL_reentrant_buffer->_localtime_struct : 0)
+# define localtime(a) ( L_R_TZSET localtime_r(a, &PL_reentrant_buffer->_localtime_struct) == 0 ? &PL_reentrant_buffer->_localtime_struct : 0)
# endif
#endif /* HAS_LOCALTIME_R */

--- perl-5.8.7/config_h.SH.orig 2005-04-30 10​:34​:20.000000000 -0400
+++ perl-5.8.7/config_h.SH 2005-11-02 22​:19​:27.000000000 -0500
@​@​ -1916,7 +1916,18 @​@​
*/
#$d_localtime_r HAS_LOCALTIME_R /**/
#define LOCALTIME_R_PROTO $localtime_r_proto /**/
-
+/* LOCALTIME_R_NEEDS_TZSET :
+ * many libc's localtime_r implementations do not call tzset,
+ * making them differ from localtime(), and making timezone
+ * changes using $ENV{TZ} without explicitly calling tzset
+ * impossible. This symbol makes us call tzset before localtime_r​:
+ */
+#$d_localtime_r_needs_tzset LOCALTIME_R_NEEDS_TZSET /**/
+#ifdef LOCALTIME_R_NEEDS_TZSET
+#define L_R_TZSET tzset(),
+#else
+#define L_R_TZSET
+#endif
/* HAS_LONG_DOUBLE​:
* This symbol will be defined if the C compiler supports long
* doubles.
--- perl-5.8.7/Configure.orig 2005-11-02 22​:19​:11.000000000 -0500
+++ perl-5.8.7/Configure 2005-11-02 22​:19​:41.000000000 -0500
@​@​ -528,6 +528,7 @​@​
d_libm_lib_version=''
d_link=''
d_localtime_r=''
+d_localtime_r_needs_tzset=''
localtime_r_proto=''
d_locconv=''
d_lockf=''
@​@​ -14023,7 +14024,51 @​@​
*) localtime_r_proto=0
;;
esac
+​: see if localtime_r calls tzset
+case "$localtime_r_proto" in
+REENTRANT_PROTO*)
+ $cat >try.c <<EOCP
+/* Does our libc's localtime_r call tzset ?
+ * return 0 if so, 1 otherwise.
+ */
+#include <sys/types.h>
+#include <unistd.h>
+#include <time.h>
+#include <string.h>
+#include <malloc.h>
+int main()
+{
+ time_t t = time(0L);
+ char w_tz[]="TZ=US/Eastern",
+ e_tz[]="TZ=US/Western",
+ *tz_e = (char*)malloc(16),
+ *tz_w = (char*)malloc(16);
+ struct tm tm_e, tm_w;
+
+ strcpy(tz_e,e_tz);
+ strcpy(tz_w,w_tz);
+
+ putenv(tz_e);
+ localtime_r(&t, &tm_e);
+
+ putenv(tz_w);
+ localtime_r(&t, &tm_w);

+ if( memcmp(&tm_e, &tm_w, sizeof(struct tm)) == 0 )
+ return 1;
+ return 0;
+}
+EOCP
+ set try
+ if eval $compile; then
+ if ./try; then
+ d_localtime_r_needs_tzset=undef;
+ else
+ d_localtime_r_needs_tzset=define;
+ fi;
+ fi;
+ ;;
+esac
: see if localeconv exists
set localeconv d_locconv
eval $inlibc
@​@​ -20769,6 +20814,7 @​@​
d_libm_lib_version='$d_libm_lib_version'
d_link='$d_link'
d_localtime_r='$d_localtime_r'
+d_localtime_r_needs_tzset='$d_localtime_r_needs_tzset'
d_locconv='$d_locconv'
d_lockf='$d_lockf'
d_longdbl='$d_longdbl'
___ END PATCH

@p5pRT
Copy link
Author

p5pRT commented Jul 14, 2006

From bah@longitude.com

Although a patch for this bug exists in fedora core 5 (bug 172396​:
https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=172396 ) it, or its
moral equivalent, does not seem to have made it back upstream. We ran
into this issue building a threaded perl on CentOS and have applied the
fedora patch which appears to work fine. I am attaching this patch,
reworked to go against perl-current and also to include a test.

Ben

@p5pRT
Copy link
Author

p5pRT commented Jul 14, 2006

From bah@longitude.com

26136.patch
diff -urp perl-current/config_h.SH perl-patched/config_h.SH
--- perl-current/config_h.SH	2006-06-13 15:28:57.000000000 -0400
+++ perl-patched/config_h.SH	2006-07-14 10:28:02.328011092 -0400
@@ -2284,7 +2284,18 @@ sed <<!GROK!THIS! >$CONFIG_H -e 's!^#und
  */
 #$d_localtime_r HAS_LOCALTIME_R	   /**/
 #define LOCALTIME_R_PROTO $localtime_r_proto	   /**/
-
+/* LOCALTIME_R_NEEDS_TZSET :
+ *  many libc's localtime_r implementations do not call tzset,
+ *  making them differ from localtime(), and making timezone
+ *  changes using $ENV{TZ} without explicitly calling tzset
+ *  impossible. This symbol makes us call tzset before localtime_r:
+ */
+#$d_localtime_r_needs_tzset LOCALTIME_R_NEEDS_TZSET /**/
+#ifdef LOCALTIME_R_NEEDS_TZSET
+#define L_R_TZSET tzset(),
+#else
+#define L_R_TZSET
+#endif 
 /* HAS_LONG_DOUBLE:
  *	This symbol will be defined if the C compiler supports long
  *	doubles.
diff -urp perl-current/Configure perl-patched/Configure
--- perl-current/Configure	2006-06-13 15:28:55.000000000 -0400
+++ perl-patched/Configure	2006-07-14 10:28:02.350008665 -0400
@@ -547,6 +547,7 @@ d_ldbl_dig=''
 d_libm_lib_version=''
 d_link=''
 d_localtime_r=''
+d_localtime_r_needs_tzset=''
 localtime_r_proto=''
 d_locconv=''
 d_lockf=''
@@ -14475,7 +14476,55 @@ case "$d_localtime_r" in
 *)	localtime_r_proto=0
 	;;
 esac
+: see if localtime_r calls tzset
+case "$localtime_r_proto" in
+REENTRANT_PROTO*) 
+	$cat >try.c <<EOCP
+/*  Does our libc's localtime_r call tzset ?
+ *  return 0 if so, 1 otherwise.
+ */ 
+#include <sys/types.h>
+#include <unistd.h>
+#include <time.h>
+#include <string.h>
+#include <malloc.h>
+int main()
+{
+    time_t t = time(0L);
+    char w_tz[]="TZ=GMT+5",
+	 e_tz[]="TZ=GMT-5",
+	*tz_e = (char*)malloc(16),
+	*tz_w = (char*)malloc(16);
+    struct tm tm_e, tm_w;
+
+    strcpy(tz_e,e_tz);
+    strcpy(tz_w,w_tz);
+
+    putenv(tz_e);
+    localtime_r(&t, &tm_e);    
+    
+    putenv(tz_w);
+    localtime_r(&t, &tm_w);    
 
+    if( memcmp(&tm_e, &tm_w, sizeof(struct tm)) == 0 )
+	return 1;
+    return 0;
+}
+EOCP
+	set try
+	if eval $compile; then	
+	    if ./try; then
+		d_localtime_r_needs_tzset=undef;
+	    else
+		d_localtime_r_needs_tzset=define;
+	    fi;
+	    rm -f ./try;
+	else
+	    d_localtime_r_needs_tzset=undef;
+	fi;
+	rm -f try.c;
+     ;;
+esac
 : see if localeconv exists
 set localeconv d_locconv
 eval $inlibc
@@ -21465,6 +21514,7 @@ d_ldbl_dig='$d_ldbl_dig'
 d_libm_lib_version='$d_libm_lib_version'
 d_link='$d_link'
 d_localtime_r='$d_localtime_r'
+d_localtime_r_needs_tzset='$d_localtime_r_needs_tzset'
 d_locconv='$d_locconv'
 d_lockf='$d_lockf'
 d_longdbl='$d_longdbl'
diff -urp perl-current/reentr.h perl-patched/reentr.h
--- perl-current/reentr.h	2006-06-13 15:29:30.000000000 -0400
+++ perl-patched/reentr.h	2006-07-14 10:28:02.325011423 -0400
@@ -1265,10 +1265,10 @@ typedef struct {
 #ifdef HAS_LOCALTIME_R
 #   undef localtime
 #   if !defined(localtime) && LOCALTIME_R_PROTO == REENTRANT_PROTO_S_TS
-#       define localtime(a) (localtime_r(a, &PL_reentrant_buffer->_localtime_struct) ? &PL_reentrant_buffer->_localtime_struct : 0)
+#       define localtime(a) ( L_R_TZSET localtime_r(a, &PL_reentrant_buffer->_localtime_struct) ? &PL_reentrant_buffer->_localtime_struct : 0)
 #   endif
 #   if !defined(localtime) && LOCALTIME_R_PROTO == REENTRANT_PROTO_I_TS
-#       define localtime(a) (localtime_r(a, &PL_reentrant_buffer->_localtime_struct) == 0 ? &PL_reentrant_buffer->_localtime_struct : 0)
+#       define localtime(a) ( L_R_TZSET localtime_r(a, &PL_reentrant_buffer->_localtime_struct) == 0 ? &PL_reentrant_buffer->_localtime_struct : 0)
 #   endif
 #endif /* HAS_LOCALTIME_R */
 
diff -urp perl-current/t/op/time.t perl-patched/t/op/time.t
--- perl-current/t/op/time.t	2006-07-14 10:05:38.752400243 -0400
+++ perl-patched/t/op/time.t	2006-07-14 10:15:28.062278000 -0400
@@ -1,10 +1,10 @@
 #!./perl
 
 if ( $does_gmtime = gmtime(time) ) { 
-    print "1..7\n" 
+    print "1..8\n" 
 }
 else { 
-    print "1..4\n" 
+    print "1..5\n" 
 }
 
 
@@ -52,6 +52,13 @@ ok(localtime() =~ /^(Sun|Mon|Tue|Wed|Thu
    'localtime(), scalar context'
   );
 
+# check that localtime respects changes to $ENV{TZ}
+$ENV{TZ} = "GMT-5";
+($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($beg);
+$ENV{TZ} = "GMT+5";
+($sec,$min,$hour2,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($beg);
+ok($hour != $hour2,                             'changes to $ENV{TZ} respected');
+
 exit 0 unless $does_gmtime;
 
 ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = gmtime($beg);

@p5pRT
Copy link
Author

p5pRT commented Jul 14, 2006

From jvdias@redhat.com

On Friday 14 July 2006 10​:49, bah@​longitude.com wrote​:

Although a patch for this bug exists in fedora core 5 (bug 172396​:
https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=172396 ) it, or its
moral equivalent, does not seem to have made it back upstream. We ran
into this issue building a threaded perl on CentOS and have applied the
fedora patch which appears to work fine. I am attaching this patch,
reworked to go against perl-current and also to include a test.

Ben

Here's the latest version of the Fedora patch, which corrects
an issue with the original patch on some 64-bit platforms where
the uninitialized extra pad bytes in 'struct tm' could cause the
memcmp() to fail. This patch should be combined with the t/op/time.t
patch from the '26136.patch' of the previous mail.

This patch has been applied to perl-5.8.7 in FC-4, perl-5.8.8 in FC-5 and FC-6,
and perl-5.8.5 in RHEL-4 for some months now and no issues with it have been
reported.

It would be great to get this into the next perl-5.8.9 / maint release
(and perl-current).

Regards,

Jason Vas Dias<jvdias@​redhat.com>
perl package maintainer
Red Hat, Inc.

@p5pRT
Copy link
Author

p5pRT commented Jul 14, 2006

From jvdias@redhat.com

perl-5.8.8-172396.patch
--- perl-5.8.8/config_h.SH.bz172396	2005-10-31 13:13:05.000000000 -0500
+++ perl-5.8.8/config_h.SH	2006-05-11 16:20:36.000000000 -0400
@@ -1912,7 +1912,18 @@
  */
 #$d_localtime_r HAS_LOCALTIME_R	   /**/
 #define LOCALTIME_R_PROTO $localtime_r_proto	   /**/
-
+/* LOCALTIME_R_NEEDS_TZSET :
+ *  many libc's localtime_r implementations do not call tzset,
+ *  making them differ from localtime(), and making timezone
+ *  changes using $ENV{TZ} without explicitly calling tzset
+ *  impossible. This symbol makes us call tzset before localtime_r:
+ */
+#$d_localtime_r_needs_tzset LOCALTIME_R_NEEDS_TZSET /**/
+#ifdef LOCALTIME_R_NEEDS_TZSET
+#define L_R_TZSET tzset(),
+#else
+#define L_R_TZSET
+#endif 
 /* HAS_LONG_DOUBLE:
  *	This symbol will be defined if the C compiler supports long
  *	doubles.
--- perl-5.8.8/reentr.inc.bz172396	2006-05-11 16:20:36.000000000 -0400
+++ perl-5.8.8/reentr.inc	2006-05-11 16:20:36.000000000 -0400
@@ -1368,10 +1368,10 @@
 #ifdef HAS_LOCALTIME_R
 #   undef localtime
 #   if !defined(localtime) && LOCALTIME_R_PROTO == REENTRANT_PROTO_S_TS
-#       define localtime(a) (localtime_r(a, &PL_reentrant_buffer->_localtime_struct) ? &PL_reentrant_buffer->_localtime_struct : 0)
+#       define localtime(a) ( L_R_TZSET localtime_r(a, &PL_reentrant_buffer->_localtime_struct) ? &PL_reentrant_buffer->_localtime_struct : 0)
 #   endif
 #   if !defined(localtime) && LOCALTIME_R_PROTO == REENTRANT_PROTO_I_TS
-#       define localtime(a) (localtime_r(a, &PL_reentrant_buffer->_localtime_struct) == 0 ? &PL_reentrant_buffer->_localtime_struct : 0)
+#       define localtime(a) ( L_R_TZSET localtime_r(a, &PL_reentrant_buffer->_localtime_struct) == 0 ? &PL_reentrant_buffer->_localtime_struct : 0)
 #   endif
 #endif /* HAS_LOCALTIME_R */
 
--- perl-5.8.8/Configure.bz172396	2006-05-11 16:20:36.000000000 -0400
+++ perl-5.8.8/Configure	2006-05-11 16:21:47.000000000 -0400
@@ -542,6 +542,7 @@
 d_libm_lib_version=''
 d_link=''
 d_localtime_r=''
+d_localtime_r_needs_tzset=''
 localtime_r_proto=''
 d_locconv=''
 d_lockf=''
@@ -14261,7 +14262,59 @@
 *)	localtime_r_proto=0
 	;;
 esac
+: see if localtime_r calls tzset
+case "$localtime_r_proto" in
+REENTRANT_PROTO*) 
+	$cat >try.c <<EOCP
+/*  Does our libc's localtime_r call tzset ?
+ *  return 0 if so, 1 otherwise.
+ */ 
+#include <sys/types.h>
+#include <unistd.h>
+#include <time.h>
+#include <string.h>
+#include <malloc.h>
+int main()
+{
+    time_t t = time(0L);
+    char w_tz[]="TZ=GMT+5",
+	 e_tz[]="TZ=GMT-5",
+	*tz_e = (char*)malloc(16),
+	*tz_w = (char*)malloc(16);
+    struct tm tm_e, tm_w;
+    memset(&tm_e,'\0',sizeof(struct tm));
+    memset(&tm_w,'\0',sizeof(struct tm));
+    strcpy(tz_e,e_tz);
+    strcpy(tz_w,w_tz);
 
+    putenv(tz_e);
+    localtime_r(&t, &tm_e);    
+    
+    putenv(tz_w);
+    localtime_r(&t, &tm_w);    
+
+    if( memcmp(&tm_e, &tm_w, sizeof(struct tm)) == 0 )
+	return 1;
+    return 0;
+}
+EOCP
+	set try
+	if eval $compile; then	
+	    if ./try; then
+		d_localtime_r_needs_tzset=undef;
+	    else
+		d_localtime_r_needs_tzset=define;
+	    fi;
+	    rm -f ./try;
+	else
+	    d_localtime_r_needs_tzset=undef;
+	fi;
+	rm -f try.c;
+     ;;
+  *)
+     d_localtime_r_needs_tzset=undef;
+     ;;
+esac
 : see if localeconv exists
 set localeconv d_locconv
 eval $inlibc
@@ -21220,6 +21273,7 @@
 d_libm_lib_version='$d_libm_lib_version'
 d_link='$d_link'
 d_localtime_r='$d_localtime_r'
+d_localtime_r_needs_tzset='$d_localtime_r_needs_tzset'
 d_locconv='$d_locconv'
 d_lockf='$d_lockf'
 d_longdbl='$d_longdbl'

@p5pRT
Copy link
Author

p5pRT commented Jul 14, 2006

From bholzman@longitude.com

-----Original Message-----
From​: Jason Vas Dias [mailto​:jvdias@​redhat.com]
Sent​: Friday, July 14, 2006 11​:30 AM

Here's the latest version of the Fedora patch, which corrects
an issue with the original patch on some 64-bit platforms where
the uninitialized extra pad bytes in 'struct tm' could cause the
memcmp() to fail. This patch should be combined with the t/op/time.t
patch from the '26136.patch' of the previous mail.

This patches reentr.inc which is a generated file. I had changed the patch
to go against reentr.h, but otherwise it should apply cleanly.

Ben

@p5pRT
Copy link
Author

p5pRT commented Jul 19, 2006

From bholzman@longitude.com

This patches reentr.inc which is a generated file. I had changed the
patch
to go against reentr.h, but otherwise it should apply cleanly.

I am attaching a combined patch that includes Jason's last version, modified
to go against reentr.h, as well as the t/op/time.t change.

Ben

@p5pRT
Copy link
Author

p5pRT commented Jul 19, 2006

From bholzman@longitude.com

26136.patch
diff -urp perl-current/config_h.SH perl-patched/config_h.SH
--- perl-current/config_h.SH	2006-06-13 15:28:57.000000000 -0400
+++ perl-patched/config_h.SH	2006-07-14 10:28:02.328011092 -0400
@@ -2284,7 +2284,18 @@ sed <<!GROK!THIS! >$CONFIG_H -e 's!^#und
  */
 #$d_localtime_r HAS_LOCALTIME_R	   /**/
 #define LOCALTIME_R_PROTO $localtime_r_proto	   /**/
-
+/* LOCALTIME_R_NEEDS_TZSET :
+ *  many libc's localtime_r implementations do not call tzset,
+ *  making them differ from localtime(), and making timezone
+ *  changes using $ENV{TZ} without explicitly calling tzset
+ *  impossible. This symbol makes us call tzset before localtime_r:
+ */
+#$d_localtime_r_needs_tzset LOCALTIME_R_NEEDS_TZSET /**/
+#ifdef LOCALTIME_R_NEEDS_TZSET
+#define L_R_TZSET tzset(),
+#else
+#define L_R_TZSET
+#endif 
 /* HAS_LONG_DOUBLE:
  *	This symbol will be defined if the C compiler supports long
  *	doubles.
diff -urp perl-current/Configure perl-patched/Configure
--- perl-current/Configure	2006-06-13 15:28:55.000000000 -0400
+++ perl-patched/Configure	2006-07-14 10:28:02.350008665 -0400
@@ -547,6 +547,7 @@ d_ldbl_dig=''
 d_libm_lib_version=''
 d_link=''
 d_localtime_r=''
+d_localtime_r_needs_tzset=''
 localtime_r_proto=''
 d_locconv=''
 d_lockf=''
@@ -14475,7 +14476,59 @@ case "$d_localtime_r" in
 *)	localtime_r_proto=0
 	;;
 esac
+: see if localtime_r calls tzset
+case "$localtime_r_proto" in
+REENTRANT_PROTO*) 
+	$cat >try.c <<EOCP
+/*  Does our libc's localtime_r call tzset ?
+ *  return 0 if so, 1 otherwise.
+ */ 
+#include <sys/types.h>
+#include <unistd.h>
+#include <time.h>
+#include <string.h>
+#include <malloc.h>
+int main()
+{
+    time_t t = time(0L);
+    char w_tz[]="TZ=GMT+5",
+	 e_tz[]="TZ=GMT-5",
+	*tz_e = (char*)malloc(16),
+	*tz_w = (char*)malloc(16);
+    struct tm tm_e, tm_w;
+    memset(&tm_e,'\0',sizeof(struct tm));
+    memset(&tm_w,'\0',sizeof(struct tm));
+    strcpy(tz_e,e_tz);
+    strcpy(tz_w,w_tz);
+
+    putenv(tz_e);
+    localtime_r(&t, &tm_e);    
+    
+    putenv(tz_w);
+    localtime_r(&t, &tm_w);    
 
+    if( memcmp(&tm_e, &tm_w, sizeof(struct tm)) == 0 )
+	return 1;
+    return 0;
+}
+EOCP
+	set try
+	if eval $compile; then	
+	    if ./try; then
+		d_localtime_r_needs_tzset=undef;
+	    else
+		d_localtime_r_needs_tzset=define;
+	    fi;
+	    rm -f ./try;
+	else
+	    d_localtime_r_needs_tzset=undef;
+	fi;
+	rm -f try.c;
+     ;;
+  *)
+     d_localtime_r_needs_tzset=undef;
+     ;;
+esac
 : see if localeconv exists
 set localeconv d_locconv
 eval $inlibc
@@ -21465,6 +21514,7 @@ d_ldbl_dig='$d_ldbl_dig'
 d_libm_lib_version='$d_libm_lib_version'
 d_link='$d_link'
 d_localtime_r='$d_localtime_r'
+d_localtime_r_needs_tzset='$d_localtime_r_needs_tzset'
 d_locconv='$d_locconv'
 d_lockf='$d_lockf'
 d_longdbl='$d_longdbl'
diff -urp perl-current/reentr.h perl-patched/reentr.h
--- perl-current/reentr.h	2006-06-13 15:29:30.000000000 -0400
+++ perl-patched/reentr.h	2006-07-14 10:28:02.325011423 -0400
@@ -1265,10 +1265,10 @@ typedef struct {
 #ifdef HAS_LOCALTIME_R
 #   undef localtime
 #   if !defined(localtime) && LOCALTIME_R_PROTO == REENTRANT_PROTO_S_TS
-#       define localtime(a) (localtime_r(a, &PL_reentrant_buffer->_localtime_struct) ? &PL_reentrant_buffer->_localtime_struct : 0)
+#       define localtime(a) ( L_R_TZSET localtime_r(a, &PL_reentrant_buffer->_localtime_struct) ? &PL_reentrant_buffer->_localtime_struct : 0)
 #   endif
 #   if !defined(localtime) && LOCALTIME_R_PROTO == REENTRANT_PROTO_I_TS
-#       define localtime(a) (localtime_r(a, &PL_reentrant_buffer->_localtime_struct) == 0 ? &PL_reentrant_buffer->_localtime_struct : 0)
+#       define localtime(a) ( L_R_TZSET localtime_r(a, &PL_reentrant_buffer->_localtime_struct) == 0 ? &PL_reentrant_buffer->_localtime_struct : 0)
 #   endif
 #endif /* HAS_LOCALTIME_R */
 
diff -urp perl-current/t/op/time.t perl-patched/t/op/time.t
--- perl-current/t/op/time.t	2006-07-14 10:05:38.752400243 -0400
+++ perl-patched/t/op/time.t	2006-07-14 10:15:28.062278000 -0400
@@ -1,10 +1,10 @@
 #!./perl
 
 if ( $does_gmtime = gmtime(time) ) { 
-    print "1..7\n" 
+    print "1..8\n" 
 }
 else { 
-    print "1..4\n" 
+    print "1..5\n" 
 }
 
 
@@ -52,6 +52,13 @@ ok(localtime() =~ /^(Sun|Mon|Tue|Wed|Thu
    'localtime(), scalar context'
   );
 
+# check that localtime respects changes to $ENV{TZ}
+$ENV{TZ} = "GMT-5";
+($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($beg);
+$ENV{TZ} = "GMT+5";
+($sec,$min,$hour2,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($beg);
+ok($hour != $hour2,                             'changes to $ENV{TZ} respected');
+
 exit 0 unless $does_gmtime;
 
 ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = gmtime($beg);

@p5pRT
Copy link
Author

p5pRT commented Jul 24, 2006

From bholzman@longitude.com

There have been no comments on this patch. Is there something wrong with it
or can it be accepted?

Thanks,

Ben

-----Original Message-----
From​: Benjamin Holzman [mailto​:bholzman@​longitude.com]
Sent​: Wednesday, July 19, 2006 7​:11 AM
To​: 'Benjamin Holzman'; 'jvdias@​redhat.com'; 'perl5-porters@​perl.org'
Cc​: 'bah@​longitude.com'; 'gp@​familiehaase.de'; 'sagawa@​sohgoh.net';
'wia@​iglass.net'
Subject​: RE​: [perl #26136] localtime(3) calls tzset(3), but localtime_r(3)
may not.

This patches reentr.inc which is a generated file. I had changed the
patch
to go against reentr.h, but otherwise it should apply cleanly.

I am attaching a combined patch that includes Jason's last version,
modified to go against reentr.h, as well as the t/op/time.t change.

Ben

@p5pRT
Copy link
Author

p5pRT commented Nov 6, 2006

From @Tux

This has now been applied to devel in #29207

Change 29209 by merijn@​merijn-lt09 on 2006/11/06 09​:43​:30

  RE​: [perl #26136] localtime(3) calls tzset(3), but localtime_r(3) may not.
  From​: "Benjamin Holzman" <bholzman@​longitude.com>
  Date​: Wed, 19 Jul 2006 07​:11​:09 -0400
  Message-ID​: <010801c6ab24$09b9ed30$ce0515ac@​office.iseoptions.com>

Affected files ...

... //depot/perl/Configure#627 edit
... //depot/perl/Porting/Glossary#172 edit
... //depot/perl/config_h.SH#324 edit
... //depot/perl/reentr.h#31 edit
... //depot/perl/t/op/time.t#12 edit

--
H.Merijn Brand Amsterdam Perl Mongers (http​://amsterdam.pm.org/)
using & porting perl 5.6.2, 5.8.x, 5.9.x on HP-UX 10.20, 11.00, 11.11,
& 11.23, SuSE 10.0 & 10.1, AIX 4.3 & 5.2, and Cygwin. http​://qa.perl.org
http​://mirrors.develooper.com/hpux/ http​://www.test-smoke.org
  http​://www.goldmark.org/jeff/stupid-disclaimers/

@p5pRT p5pRT closed this as completed Nov 6, 2006
@p5pRT
Copy link
Author

p5pRT commented Nov 6, 2006

@rgs - Status changed from 'open' to 'resolved'

@p5pRT
Copy link
Author

p5pRT commented Nov 6, 2006

From @demerphq

On 11/6/06, H.Merijn Brand <h.m.brand@​xs4all.nl> wrote​:

This has now been applied to devel in #29207

Change 29209 by merijn@​merijn-lt09 on 2006/11/06 09​:43​:30

    RE&#8203;: \[perl \#26136\] localtime\(3\) calls tzset\(3\)\, but localtime\_r\(3\) may not\.
    From&#8203;: "Benjamin Holzman" \<bholzman@&#8203;longitude\.com>
    Date&#8203;: Wed\, 19 Jul 2006 07&#8203;:11&#8203;:09 \-0400
    Message\-ID&#8203;: \<010801c6ab24$09b9ed30$ce0515ac@&#8203;office\.iseoptions\.com>

Affected files ...

... //depot/perl/Configure#627 edit
... //depot/perl/Porting/Glossary#172 edit
... //depot/perl/config_h.SH#324 edit
... //depot/perl/reentr.h#31 edit
... //depot/perl/t/op/time.t#12 edit

The new test fails on Win32. Is it supposed to pass or should it be skipped?

I'd guess that since Win32 doesnt support the TZ environment var it
should be skipped.

Yves

--
perl -Mre=debug -e "/just|another|perl|hacker/"

@p5pRT
Copy link
Author

p5pRT commented Nov 6, 2006

From @Tux

On Mon, 6 Nov 2006 12​:54​:47 +0100, demerphq <demerphq@​gmail.com> wrote​:

On 11/6/06, H.Merijn Brand <h.m.brand@​xs4all.nl> wrote​:

This has now been applied to devel in #29207

Change 29209 by merijn@​merijn-lt09 on 2006/11/06 09​:43​:30

    RE&#8203;: \[perl \#26136\] localtime\(3\) calls tzset\(3\)\, but localtime\_r\(3\) may not\.
    From&#8203;: "Benjamin Holzman" \<bholzman@&#8203;longitude\.com>
    Date&#8203;: Wed\, 19 Jul 2006 07&#8203;:11&#8203;:09 \-0400
    Message\-ID&#8203;: \<010801c6ab24$09b9ed30$ce0515ac@&#8203;office\.iseoptions\.com>

Affected files ...

... //depot/perl/Configure#627 edit
... //depot/perl/Porting/Glossary#172 edit
... //depot/perl/config_h.SH#324 edit
... //depot/perl/reentr.h#31 edit
... //depot/perl/t/op/time.t#12 edit

The new test fails on Win32. Is it supposed to pass or should it be skipped?

I'd guess that since Win32 doesnt support the TZ environment var it
should be skipped.

No, it means that even if I /thought/ about it, I forgot to update the
non-unix Configure files

Cat you check if windews needs tzset before localtime_r or not?

--
H.Merijn Brand Amsterdam Perl Mongers (http​://amsterdam.pm.org/)
using & porting perl 5.6.2, 5.8.x, 5.9.x on HP-UX 10.20, 11.00, 11.11,
& 11.23, SuSE 10.0 & 10.1, AIX 4.3 & 5.2, and Cygwin. http​://qa.perl.org
http​://mirrors.develooper.com/hpux/ http​://www.test-smoke.org
  http​://www.goldmark.org/jeff/stupid-disclaimers/

@p5pRT
Copy link
Author

p5pRT commented Nov 6, 2006

From @demerphq

On 11/6/06, H.Merijn Brand <h.m.brand@​xs4all.nl> wrote​:

On Mon, 6 Nov 2006 12​:54​:47 +0100, demerphq <demerphq@​gmail.com> wrote​:

On 11/6/06, H.Merijn Brand <h.m.brand@​xs4all.nl> wrote​:

This has now been applied to devel in #29207

Change 29209 by merijn@​merijn-lt09 on 2006/11/06 09​:43​:30

    RE&#8203;: \[perl \#26136\] localtime\(3\) calls tzset\(3\)\, but localtime\_r\(3\) may not\.
    From&#8203;: "Benjamin Holzman" \<bholzman@&#8203;longitude\.com>
    Date&#8203;: Wed\, 19 Jul 2006 07&#8203;:11&#8203;:09 \-0400
    Message\-ID&#8203;: \<010801c6ab24$09b9ed30$ce0515ac@&#8203;office\.iseoptions\.com>

Affected files ...

... //depot/perl/Configure#627 edit
... //depot/perl/Porting/Glossary#172 edit
... //depot/perl/config_h.SH#324 edit
... //depot/perl/reentr.h#31 edit
... //depot/perl/t/op/time.t#12 edit

The new test fails on Win32. Is it supposed to pass or should it be skipped?

I'd guess that since Win32 doesnt support the TZ environment var it
should be skipped.

No, it means that even if I /thought/ about it, I forgot to update the
non-unix Configure files

Cat you check if windews needs tzset before localtime_r or not?

There is the following comment in win32_putenv. Note the second
comment about USE_WIN32_RTL_ENV.

  /* The sane way to deal with the environment.
  * Has these advantages over putenv() & co.​:
  * * enables us to store a truly empty value in the
  * environment (like in UNIX).
  * * we don't have to deal with RTL globals, bugs and leaks.
  * * Much faster.
  * Why you may want to enable USE_WIN32_RTL_ENV​:
  * * environ[] and RTL functions will not reflect changes,
  * which might be an issue if extensions want to access
  * the env. via RTL. This cuts both ways, since RTL will
  * not see changes made by extensions that call the Win32
  * functions directly, either.
  * GSAR 97-06-07

But USE_WIN32_RTL_ENV is no longer supported as it was chainsawed away
in patch 8916. Anway, I think what this means is that $ENV{TZ} doesnt
set the CRTL's TZ environment so while setting it on the command line
does affect the result of localtime, setting it in perl wont.

http​://public.activestate.com/cgi-bin/perlbrowse?show_patch=Show+Patch&patch_num=8916

Yves

--
perl -Mre=debug -e "/just|another|perl|hacker/"

@p5pRT
Copy link
Author

p5pRT commented Nov 6, 2006

From BQW10602@nifty.com

On Mon, 6 Nov 2006 13​:17​:22 +0100, "H.Merijn Brand" <h.m.brand@​xs4all.nl> wrote

On Mon, 6 Nov 2006 12​:54​:47 +0100, demerphq <demerphq@​gmail.com> wrote​:

The new test fails on Win32. Is it supposed to pass or should it be skipped?

I'd guess that since Win32 doesnt support the TZ environment var it
should be skipped.

No, it means that even if I /thought/ about it, I forgot to update the
non-unix Configure files

Cat you check if windews needs tzset before localtime_r or not?

When I try it with Microsoft Visual C++ (2003), localtime() on Windows
also recognizes TZ, with call of _tzset() before localtime().
However it seems that change of TZ must be performed through _putenv(),
instead of SetEnvironmentVariableA() that is currently used
in win32_putenv().
When _putenv() was used in win32_putenv() and _tzset() was called
before localtime(), this test was passed.

As I commented on it at
http​://www.xray.mpe.mpg.de/mailing-lists/perl5-porters/2006-08/msg00
380.html
I guess this test should be skipped on some platforms;
however I must admit I'm not sure where it should be skipped.

Patch attached​: skiptzset.patch
This patch also makes t/op/time.t using t/test.pl.

Regards,
SADAHIRO Tomoyuki

@p5pRT
Copy link
Author

p5pRT commented Nov 6, 2006

From BQW10602@nifty.com

On Mon, 06 Nov 2006 23​:27​:34 +0900, SADAHIRO Tomoyuki wrote

As I commented on it at
http​://www.xray.mpe.mpg.de/mailing-lists/perl5-porters/2006-08/msg00
380.html
I guess this test should be skipped on some platforms;
however I must admit I'm not sure where it should be skipped.

Patch attached​: skiptzset.patch
This patch also makes t/op/time.t using t/test.pl.

Sorry, the attached file was empty.

Newly attached​: skiptzset.patch.gz

Regards,
SADAHIRO Tomoyuki

@p5pRT
Copy link
Author

p5pRT commented Nov 6, 2006

@p5pRT
Copy link
Author

p5pRT commented Nov 6, 2006

From @rgarcia

On 06/11/06, SADAHIRO Tomoyuki <bqw10602@​nifty.com> wrote​:

As I commented on it at
http​://www.xray.mpe.mpg.de/mailing-lists/perl5-porters/2006-08/msg00
380.html
I guess this test should be skipped on some platforms;
however I must admit I'm not sure where it should be skipped.

Patch attached​: skiptzset.patch
This patch also makes t/op/time.t using t/test.pl.

Sorry, the attached file was empty.

Newly attached​: skiptzset.patch.gz

Thanks, applied as change #29215.

@p5pRT
Copy link
Author

p5pRT commented Nov 6, 2006

From @Tux

On Mon, 06 Nov 2006 23​:31​:50 +0900, SADAHIRO Tomoyuki <bqw10602@​nifty.com>
wrote​:

On Mon, 06 Nov 2006 23​:27​:34 +0900, SADAHIRO Tomoyuki wrote

As I commented on it at
http​://www.xray.mpe.mpg.de/mailing-lists/perl5-porters/2006-08/msg00
380.html
I guess this test should be skipped on some platforms;
however I must admit I'm not sure where it should be skipped.

Patch attached​: skiptzset.patch
This patch also makes t/op/time.t using t/test.pl.

Sorry, the attached file was empty.

Newly attached​: skiptzset.patch.gz

That was applied by rgs in change #29215

I added the defaults for VMS and win32 and on in change #29213

--
H.Merijn Brand Amsterdam Perl Mongers (http​://amsterdam.pm.org/)
using & porting perl 5.6.2, 5.8.x, 5.9.x on HP-UX 10.20, 11.00, 11.11,
& 11.23, SuSE 10.0 & 10.1, AIX 4.3 & 5.2, and Cygwin. http​://qa.perl.org
http​://mirrors.develooper.com/hpux/ http​://www.test-smoke.org
  http​://www.goldmark.org/jeff/stupid-disclaimers/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant