Perl / perl5

🐪 The Perl programming language
https://dev.perl.org/perl5/
Other
1.91k stars 542 forks source link

In %Config, sGMTIME_max is too big. #16767

Open p5pRT opened 5 years ago

p5pRT commented 5 years ago

Migrated from rt.perl.org#133688 (status was 'open')

Searchable as RT133688$

p5pRT commented 5 years ago

From @joeinwap

Created by @joeinwap

The valu for $Config{sGMTIME_max} is too big. That number\, when fed into gmtime() produces undef.

#!/usr/local/bin/perl use strict;

# One-liner to fond (base 2) when GMTIME stops returning dates. # perl -le 'for (32..65) {print "$_ ".scalar gmtime 2**$_}'

# Now narow it down my $format = "%.9f %17d %s";

for ($_=55.85; $_ \< 55.95 ; $_+=0.01 ) {   printf "$format\n"\, $_\, 2**$_\, scalar gmtime 2**$_ ||"undef" }

# The value in %Config is wrong use Config; $_=$Config{sGMTIME_max}; printf "\n$format perl $^V \$Config{sGMTIME_max}\n"\,   log($_)/log(2)\, $_\, scalar gmtime $_ ||"undef";

$_=67767976233316804; printf "$format Actual value\n\n"\, log($_)/log(2)\, $_\, scalar gmtime $_;

system "uname -srvm";

==========================================

zathras> ./gmtime-test.pl 55.850000000 64941939961306016 Sat Jul 24 05​:26​:56 2057930123 55.860000000 65393646875487224 Thu Nov 4 17​:33​:44 2072244145 55.870000000 65848495659720976 Tue Jan 10 22​:56​:16 2086657730 55.880000000 66306508167441704 Wed Aug 14 04​:01​:44 2101171568 55.890000000 66767706404086488 Tue Dec 9 22​:14​:48 2115786358 55.900000000 67232112528152320 Sun Mar 2 07​:38​:40 2130502803 55.910000000 67699748852260744 Sat May 10 06​:39​:04 2145321608 55.920000000 68170637844229840 undef 55.930000000 68644802128153736 undef 55.940000000 69122264485489576 undef 55.950000000 69603047856152056 undef

55.911454483 67768036191676799 undef perl v5.28.0 $Config{sGMTIME_max} 55.911453207 67767976233316804 Sun Dec 29 12​:00​:00 2147483647 Actual value

Linux 4.15.0-39-generic #42-Ubuntu SMP Tue Oct 23 15​:48​:01 UTC 2018 x86_64

Perl Info ``` Flags: category=library severity=low module=Config Site configuration information for perl 5.28.0: Configured by jms at Sat Nov 17 00:28:12 PST 2018. Summary of my perl5 (revision 5 version 28 subversion 0) configuration: Platform: osname=linux osvers=4.15.0-38-generic archname=x86_64-linux uname='linux zathras 4.15.0-38-generic #41-ubuntu smp wed oct 10 10:59:38 utc 2018 x86_64 x86_64 x86_64 gnulinux ' config_args='' hint=recommended useposix=true d_sigaction=define useithreads=undef usemultiplicity=undef use64bitint=define use64bitall=define uselongdouble=undef usemymalloc=n default_inc_excludes_dot=define bincompat5005=undef Compiler: cc='cc' ccflags ='-fwrapv -fno-strict-aliasing -pipe -fstack-protector-strong -I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64' optimize='-O2' cppflags='-fwrapv -fno-strict-aliasing -pipe -fstack-protector-strong -I/usr/local/include' ccversion='' gccversion='7.3.0' gccosandvers='' intsize=4 longsize=8 ptrsize=8 doublesize=8 byteorder=12345678 doublekind=3 d_longlong=define longlongsize=8 d_longdbl=define longdblsize=16 longdblkind=3 ivtype='long' ivsize=8 nvtype='double' nvsize=8 Off_t='off_t' lseeksize=8 alignbytes=8 prototype=define Linker and Libraries: ld='cc' ldflags =' -fstack-protector-strong -L/usr/local/lib' libpth=/usr/local/lib /usr/lib/gcc/x86_64-linux-gnu/7/include-fixed /usr/include/x86_64-linux-gnu /usr/lib /lib/x86_64-linux-gnu /lib/../lib /usr/lib/x86_64-linux-gnu /usr/lib/../lib /lib libs=-lpthread -lnsl -ldl -lm -lcrypt -lutil -lc perllibs=-lpthread -lnsl -ldl -lm -lcrypt -lutil -lc libc=libc-2.27.so so=so useshrplib=false libperl=libperl.a gnulibc_version='2.27' Dynamic Linking: dlsrc=dl_dlopen.xs dlext=so d_dlsymun=undef ccdlflags='-Wl,-E' cccdlflags='-fPIC' lddlflags='-shared -O2 -L/usr/local/lib -fstack-protector-strong' @INC for perl 5.28.0: /usr/local/lib/perl5/site_perl/5.28.0/x86_64-linux /usr/local/lib/perl5/site_perl/5.28.0 /usr/local/lib/perl5/5.28.0/x86_64-linux /usr/local/lib/perl5/5.28.0 Environment for perl 5.28.0: HOME=/home/jms LANG=en_US.UTF-8 LANGUAGE (unset) LD_LIBRARY_PATH (unset) LOGDIR (unset) PATH=/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin:/home/jms/bin:/home/jms/bin.x64 PERL_BADLANG (unset) SHELL=/bin/tcsh ```
p5pRT commented 5 years ago

From @trwyant

FWIW\, sGMTIME_min\, sLOCALTIME_max\, and sLOCALTIME_min seem also to be affected. I don't understand the "time_size.U" annotation in the docs -- on my system (Darwin) the values appear to be determined by test programs generated and run by the Configure script.

p5pRT commented 5 years ago

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

p5pRT commented 5 years ago

From @tonycoz

On Tue\, 27 Nov 2018 09​:22​:55 -0800\, wyant wrote​:

FWIW\, sGMTIME_min\, sLOCALTIME_max\, and sLOCALTIME_min seem also to be affected. I don't understand the "time_size.U" annotation in the docs -- on my system (Darwin) the values appear to be determined by test programs generated and run by the Configure script.

time_size.U refers to​:

https://github.com/perl5-metaconfig/metaconfig/blob/master/U/perl/time_size.U

I'm seeing too large a value on Linux 64-bit too​:

tony@​mars​:.../git/perl$ ./perl -Ilib '-V​:.*GMTIME.*' sGMTIME_max='67768036191676799'; sGMTIME_min='-62167219200'; tony@​mars​:.../git/perl$ ./perl -wle 'print gmtime 67768036191676799' gmtime(67768036191676800) too large at -e line 1. gmtime(67768036191676800) failed at -e line 1.

though the output there might indicate a type selection problem - time_t is 64-bits\, but NV is a double (and Time64_T ends up as NV) losing some precision here (but not much it seems.)

Tony

p5pRT commented 5 years ago

From @craigberry

On Tue\, Nov 27\, 2018 at 4​:41 PM Tony Cook via RT \perlbug\-followup@&#8203;perl\.org wrote​:

On Tue\, 27 Nov 2018 09​:22​:55 -0800\, wyant wrote​:

FWIW\, sGMTIME_min\, sLOCALTIME_max\, and sLOCALTIME_min seem also to be affected. I don't understand the "time_size.U" annotation in the docs -- on my system (Darwin) the values appear to be determined by test programs generated and run by the Configure script.

time_size.U refers to​:

https://github.com/perl5-metaconfig/metaconfig/blob/master/U/perl/time_size.U

I'm seeing too large a value on Linux 64-bit too​:

tony@​mars​:.../git/perl$ ./perl -Ilib '-V​:.*GMTIME.*' sGMTIME_max='67768036191676799'; sGMTIME_min='-62167219200'; tony@​mars​:.../git/perl$ ./perl -wle 'print gmtime 67768036191676799' gmtime(67768036191676800) too large at -e line 1. gmtime(67768036191676800) failed at -e line 1.

though the output there might indicate a type selection problem - time_t is 64-bits\, but NV is a double (and Time64_T ends up as NV) losing some precision here (but not much it seems.)

A double was chosen as the type to hold Perl's time values since the 53 bits of its mantissa will last us well past the heat death of the universe and works equally well in places where the native time_t is 32 bits or 64 bits​:

https://perl5.git.perl.org/perl.git/commit/d95a2ea538e6c332f36c34ca45b78d6ad93c3a1f?f=time64_config.h

But the min and max values determined by Configure seem to be looking only at the native time_t\, not Perl's.

p5pRT commented 5 years ago

From @joeinwap

According to Porting/README.y2038 and Porting/timecheck.c\, the value sGMTIME_max in %Config is correct. The value is legal in C code but not in Perl.

The following should countdown by seconds\, but jumps by eight.   perl -le 'print scalar gmtime 67767976233316804-$_ for (0..59)' Sun Dec 29 12​:00​:00 2147483647 Sun Dec 29 12​:00​:00 2147483647 Sun Dec 29 12​:00​:00 2147483647 Sun Dec 29 12​:00​:00 2147483647 Sun Dec 29 12​:00​:00 2147483647 Sun Dec 29 12​:00​:00 2147483647 Sun Dec 29 12​:00​:00 2147483647 Sun Dec 29 12​:00​:00 2147483647 Sun Dec 29 12​:00​:00 2147483647 Sun Dec 29 11​:59​:52 2147483647 Sun Dec 29 11​:59​:52 2147483647 Sun Dec 29 11​:59​:52 2147483647 Sun Dec 29 11​:59​:52 2147483647 Sun Dec 29 11​:59​:52 2147483647 Sun Dec 29 11​:59​:52 2147483647 Sun Dec 29 11​:59​:52 2147483647 Sun Dec 29 11​:59​:44 2147483647 Sun Dec 29 11​:59​:44 2147483647 Sun Dec 29 11​:59​:44 2147483647 Sun Dec 29 11​:59​:44 2147483647 Sun Dec 29 11​:59​:44 2147483647 Sun Dec 29 11​:59​:44 2147483647 Sun Dec 29 11​:59​:44 2147483647 Sun Dec 29 11​:59​:44 2147483647 Sun Dec 29 11​:59​:44 2147483647 ...

It's as if bits were being lost in a long int to double to long int conversion.

p5pRT commented 5 years ago

From @joeinwap

The precision of gmtime() at its max is 8 seconds. This is an understandable consequence of putting a 56-bit number into a 53-bit mantissa. But why does it stop at 67767976233316804? Perl's gmtime() is stopping 2.5 days before the system's limit of 23​:59​:59 on the 31st of December in the year 2**31-1.

The problem is an arbitrary constant in pp_sys.c (and t/op/time.t)​:

./pp_sys.c​:4762​:#define TIME_UPPER_BOUND 67767976233316800.0

That should be​: eval { GMTIME_max . ".0" } ./pp_sys.c​:4762​:#define TIME_UPPER_BOUND (67768036191676799.0-8.0)

(The fudge factor is to make sure it rounds down to a multiple of 8 seconds.)

The value for sGMTIME_min matches the native min of "1-Jan-0000" in the proleptic Gregorian calendar. Perl currently does not use that value.

In pp_sys.c at line 4755 is this comment​:   /* The 32 bit int year limits the times we can represent to these   boundaries with a few days wiggle room to account for time zone   offsets   */   /* Sat Jan 3 00​:00​:00 -2147481748 */   #define TIME_LOWER_BOUND -67768100567755200.0   /* Sun Dec 29 12​:00​:00 2147483647 */   #define TIME_UPPER_BOUND 67767976233316800.0   /* also used for​: pp_localtime() */

There is no need for any wiggle room\, the syscall will return errno=75 when the native limits are exceeded. (EOVERFLOW=Value too large for defined data type)

p5pRT commented 5 years ago

From @Leont

On Sat\, Dec 1\, 2018 at 3​:51 AM Joe Smith \joeinwap@&#8203;gmail\.com wrote​:

The precision of gmtime() at its max is 8 seconds. This is an understandable consequence of putting a 56-bit number into a 53-bit mantissa. But why does it stop at 67767976233316804? Perl's gmtime() is stopping 2.5 days before the system's limit of 23​:59​:59 on the 31st of December in the year 2**31-1.

The problem is an arbitrary constant in pp_sys.c (and t/op/time.t)​:

./pp_sys.c​:4762​:#define TIME_UPPER_BOUND 67767976233316800.0

That should be​: eval { GMTIME_max . ".0" } ./pp_sys.c​:4762​:#define TIME_UPPER_BOUND (67768036191676799.0-8.0)

(The fudge factor is to make sure it rounds down to a multiple of 8 seconds.)

The value for sGMTIME_min matches the native min of "1-Jan-0000" in the proleptic Gregorian calendar. Perl currently does not use that value.

Which is actually an invalid date​: the Gregorian calendar does not have a year zero\, the year before 1AD is 1BC.

Leon

p5pRT commented 5 years ago

From @joeinwap

On Sat\, Dec 1\, 2018 at 2​:17 PM Leon Timmermans \fawaka@&#8203;gmail\.com wrote​:

On Sat\, Dec 1\, 2018 at 3​:51 AM Joe Smith \joeinwap@&#8203;gmail\.com wrote​:

The value for sGMTIME_min matches the native min of "1-Jan-0000" in the proleptic Gregorian calendar. Perl currently does not use that value.

Which is actually an invalid date​: the Gregorian calendar does not have a year zero\, the year before 1AD is 1BC.

Leon

Which means that sGMTIME_min ought to be moved forward 366 days to 1-Jan-0001.

The values of sLOCALTIME_min and sLOCALTIME_max are unused bits of trivia that are useless for packaged binary distributions. They depend on the timezone of where is was packaged\, the month (DST or not DST)\, and the year (in 2018 California voted to change when daylight savings time ends).

p5pRT commented 5 years ago

From @tonycoz

On Sat\, Dec 01\, 2018 at 11​:44​:23PM -0800\, Joe Smith wrote​:

On Sat\, Dec 1\, 2018 at 2​:17 PM Leon Timmermans \fawaka@&#8203;gmail\.com wrote​:

On Sat\, Dec 1\, 2018 at 3​:51 AM Joe Smith \joeinwap@&#8203;gmail\.com wrote​:

The value for sGMTIME_min matches the native min of "1-Jan-0000" in the proleptic Gregorian calendar. Perl currently does not use that value.

Which is actually an invalid date​: the Gregorian calendar does not have a year zero\, the year before 1AD is 1BC.

Leon

Which means that sGMTIME_min ought to be moved forward 366 days to 1-Jan-0001.

The values of sLOCALTIME_min and sLOCALTIME_max are unused bits of trivia that are useless for packaged binary distributions. They depend on the timezone of where is was packaged\, the month (DST or not DST)\, and the year (in 2018 California voted to change when daylight savings time ends).

sGMTIME_min and sGMTIME_max are similarly fictional\, the length of the day is increasing about about 1.7ms per century[1]\, adding 1700 seconds to the length of the day in the next million years[2]\, well before the 2**31-1 year limits imposed by the implementation.

Tony

[1] https://www.scientificamerican.com/article/earth-rotation-summer-solstice/

[2] as a rough estimate\, the rate of change will slow