From: Michael G. Schwern Date: Fri, 3 Oct 2008 20:05:10 +0000 (-0400) Subject: Fix gmtime() and localtime() so they can pop times larger than 2**55 off the stack... X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=8efababc2f87779325166ff9fd8b47cde3763a95;p=p5sagit%2Fp5-mst-13.2.git Fix gmtime() and localtime() so they can pop times larger than 2**55 off the stack. Neither POPn nor SvNVx work when casted to (Time64_T). Had to use a double and then cast. Also POPq uses an SvIV so that's no good. This causes an unfortunate loss in accuracy near 2**63 up to 8 minutes. %lld is broken, it uses regular integers. Need to use doubles and %.0f instead, again losing accuracy. Now things can go out to 2**63-512. --- diff --git a/pp_sys.c b/pp_sys.c index 5cfe38a..26468e6 100644 --- a/pp_sys.c +++ b/pp_sys.c @@ -4415,11 +4415,15 @@ PP(pp_gmtime) when = (Time64_T)now; } else { - double now = POPn; - when = (Time64_T)now; - if( when != now ) { + /* XXX POPq uses an SvIV so it won't work with 32 bit integer scalars + using a double causes an unfortunate loss of accuracy on high numbers. + What we really need is an SvQV. + */ + double input = POPn; + when = (Time64_T)input; + if( when != input ) { Perl_warner(aTHX_ packWARN(WARN_OVERFLOW), - "%.0f too large for %s", now, opname); + "%s(%.0f) too large", opname, input); } } @@ -4429,25 +4433,29 @@ PP(pp_gmtime) err = gmtime64_r(&when, &tmbuf); if( err == NULL ) { + /* XXX %lld broken for quads */ Perl_warner(aTHX_ packWARN(WARN_OVERFLOW), - "%s under/overflowed the year", opname); + "%s(%.0f) failed", opname, (double)when); } if (GIMME != G_ARRAY) { /* scalar context */ SV *tsv; + /* XXX newSVpvf()'s %lld type is broken, so cheat with a double */ + double year = (double)tmbuf.tm_year + 1900; + EXTEND(SP, 1); EXTEND_MORTAL(1); if (err == NULL) RETPUSHUNDEF; - tsv = Perl_newSVpvf(aTHX_ "%s %s %2d %02d:%02d:%02d %lld", + tsv = Perl_newSVpvf(aTHX_ "%s %s %2d %02d:%02d:%02d %.0f", dayname[tmbuf.tm_wday], monname[tmbuf.tm_mon], tmbuf.tm_mday, tmbuf.tm_hour, tmbuf.tm_min, tmbuf.tm_sec, - tmbuf.tm_year + 1900); + year); mPUSHs(tsv); } else { /* list context */