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

In %Config, sGMTIME_max is too big. #16767

Open
p5pRT opened this issue Nov 27, 2018 · 10 comments
Open

In %Config, sGMTIME_max is too big. #16767

p5pRT opened this issue Nov 27, 2018 · 10 comments

Comments

@p5pRT
Copy link

p5pRT commented Nov 27, 2018

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

Searchable as RT133688$

@p5pRT
Copy link
Author

p5pRT commented Nov 27, 2018

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
Copy link
Author

p5pRT commented Nov 27, 2018

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
Copy link
Author

p5pRT commented Nov 27, 2018

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

@p5pRT
Copy link
Author

p5pRT commented Nov 27, 2018

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
Copy link
Author

p5pRT commented Nov 27, 2018

From @craigberry

On Tue, Nov 27, 2018 at 4​:41 PM Tony Cook via RT
<perlbug-followup@​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
Copy link
Author

p5pRT commented Nov 30, 2018

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
Copy link
Author

p5pRT commented Dec 1, 2018

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
Copy link
Author

p5pRT commented Dec 1, 2018

From @Leont

On Sat, Dec 1, 2018 at 3​:51 AM Joe Smith <joeinwap@​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
Copy link
Author

p5pRT commented Dec 2, 2018

From @joeinwap

On Sat, Dec 1, 2018 at 2​:17 PM Leon Timmermans <fawaka@​gmail.com> wrote​:

On Sat, Dec 1, 2018 at 3​:51 AM Joe Smith <joeinwap@​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
Copy link
Author

p5pRT commented Dec 2, 2018

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@​gmail.com> wrote​:

On Sat, Dec 1, 2018 at 3​:51 AM Joe Smith <joeinwap@​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

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

No branches or pull requests

2 participants