aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPaul Eggert2018-11-03 13:11:26 -0700
committerPaul Eggert2018-11-03 21:36:46 -0700
commitb4eb908f858284a7962851fd99c94598f76afa6f (patch)
treed4e91b37d685ec7491c34e76598a0d3b3429cf34 /src
parent07048183a86134b63cb7132038fab6f36a1e57ca (diff)
downloademacs-b4eb908f858284a7962851fd99c94598f76afa6f.tar.gz
emacs-b4eb908f858284a7962851fd99c94598f76afa6f.zip
Improve time error reporting
* src/timefns.c (emacs_mktime_z): Remove; no longer needed. (time_error): New function, replacing invalid_time. All callers changed. (decode_float_time, decode_ticks_hz, decode_time_components): Return an error number instead of merely a boolean. All callers changed. (decode_lisp_time): Signal an error based on the error number, instead of merely returning a boolean to the caller. All callers changed. (format_time_string, Fdecode_time, Fencode_time) (Fcurrent_time_string): Do not assume that a failure of a system time function must be due to time overflow. (Fencode_time): Don't report an error merely because mktime returned ((time_t) -1), as that may be a valid time_t value. Use a simpler error check. See: https://www.sourceware.org/ml/libc-alpha/2018-11/msg00062.html
Diffstat (limited to 'src')
-rw-r--r--src/timefns.c102
1 files changed, 49 insertions, 53 deletions
diff --git a/src/timefns.c b/src/timefns.c
index c94d97d9a84..f527d5ed7fd 100644
--- a/src/timefns.c
+++ b/src/timefns.c
@@ -171,16 +171,6 @@ emacs_localtime_rz (timezone_t tz, time_t const *t, struct tm *tm)
171 return tm; 171 return tm;
172} 172}
173 173
174static time_t
175emacs_mktime_z (timezone_t tz, struct tm *tm)
176{
177 errno = 0;
178 time_t t = mktime_z (tz, tm);
179 if (t == (time_t) -1 && errno == ENOMEM)
180 memory_full (SIZE_MAX);
181 return t;
182}
183
184static _Noreturn void 174static _Noreturn void
185invalid_time_zone_specification (Lisp_Object zone) 175invalid_time_zone_specification (Lisp_Object zone)
186{ 176{
@@ -347,9 +337,14 @@ time_overflow (void)
347} 337}
348 338
349static _Noreturn void 339static _Noreturn void
350invalid_time (void) 340time_error (int err)
351{ 341{
352 error ("Invalid time specification"); 342 switch (err)
343 {
344 case ENOMEM: memory_full (SIZE_MAX);
345 case EOVERFLOW: time_overflow ();
346 default: error ("Invalid time specification");
347 }
353} 348}
354 349
355static _Noreturn void 350static _Noreturn void
@@ -373,19 +368,19 @@ lo_time (time_t t)
373} 368}
374 369
375/* Convert T into an Emacs time *RESULT, truncating toward minus infinity. 370/* Convert T into an Emacs time *RESULT, truncating toward minus infinity.
376 Return true if T is in range, false otherwise. */ 371 Return zero if successful, an error number otherwise. */
377static bool 372static int
378decode_float_time (double t, struct lisp_time *result) 373decode_float_time (double t, struct lisp_time *result)
379{ 374{
380 if (!isfinite (t)) 375 if (!isfinite (t))
381 return false; 376 return isnan (t) ? EINVAL : EOVERFLOW;
382 /* Actual hz unknown; guess TIMESPEC_HZ. */ 377 /* Actual hz unknown; guess TIMESPEC_HZ. */
383 mpz_set_d (mpz[1], t); 378 mpz_set_d (mpz[1], t);
384 mpz_set_si (mpz[0], floor ((t - trunc (t)) * TIMESPEC_HZ)); 379 mpz_set_si (mpz[0], floor ((t - trunc (t)) * TIMESPEC_HZ));
385 mpz_addmul_ui (mpz[0], mpz[1], TIMESPEC_HZ); 380 mpz_addmul_ui (mpz[0], mpz[1], TIMESPEC_HZ);
386 result->ticks = make_integer_mpz (); 381 result->ticks = make_integer_mpz ();
387 result->hz = timespec_hz; 382 result->hz = timespec_hz;
388 return true; 383 return 0;
389} 384}
390 385
391/* Compute S + NS/TIMESPEC_HZ as a double. 386/* Compute S + NS/TIMESPEC_HZ as a double.
@@ -569,9 +564,9 @@ lisp_time_form_stamp (struct lisp_time t, Lisp_Object form)
569 start of the POSIX Epoch. Unsuccessful calls may or may not store 564 start of the POSIX Epoch. Unsuccessful calls may or may not store
570 results. 565 results.
571 566
572 Return true if successful, false if (TICKS . HZ) would not 567 Return zero if successful, an error number if (TICKS . HZ) would not
573 be a valid new-format timestamp. */ 568 be a valid new-format timestamp. */
574static bool 569static int
575decode_ticks_hz (Lisp_Object ticks, Lisp_Object hz, 570decode_ticks_hz (Lisp_Object ticks, Lisp_Object hz,
576 struct lisp_time *result, double *dresult) 571 struct lisp_time *result, double *dresult)
577{ 572{
@@ -581,7 +576,7 @@ decode_ticks_hz (Lisp_Object ticks, Lisp_Object hz,
581 if (! (INTEGERP (ticks) 576 if (! (INTEGERP (ticks)
582 && ((FIXNUMP (hz) && 0 < XFIXNUM (hz)) 577 && ((FIXNUMP (hz) && 0 < XFIXNUM (hz))
583 || (BIGNUMP (hz) && 0 < mpz_sgn (XBIGNUM (hz)->value))))) 578 || (BIGNUMP (hz) && 0 < mpz_sgn (XBIGNUM (hz)->value)))))
584 return false; 579 return EINVAL;
585 580
586 if (result) 581 if (result)
587 { 582 {
@@ -600,7 +595,7 @@ decode_ticks_hz (Lisp_Object ticks, Lisp_Object hz,
600 if (ns < 0) 595 if (ns < 0)
601 s--, ns += TIMESPEC_HZ; 596 s--, ns += TIMESPEC_HZ;
602 *dresult = s_ns_to_double (s, ns); 597 *dresult = s_ns_to_double (s, ns);
603 return true; 598 return 0;
604 } 599 }
605 ns = mpz_fdiv_q_ui (*q, XBIGNUM (ticks)->value, TIMESPEC_HZ); 600 ns = mpz_fdiv_q_ui (*q, XBIGNUM (ticks)->value, TIMESPEC_HZ);
606 } 601 }
@@ -610,7 +605,7 @@ decode_ticks_hz (Lisp_Object ticks, Lisp_Object hz,
610 if (FIXNUMP (ticks)) 605 if (FIXNUMP (ticks))
611 { 606 {
612 *dresult = XFIXNUM (ticks); 607 *dresult = XFIXNUM (ticks);
613 return true; 608 return 0;
614 } 609 }
615 q = &XBIGNUM (ticks)->value; 610 q = &XBIGNUM (ticks)->value;
616 } 611 }
@@ -624,7 +619,7 @@ decode_ticks_hz (Lisp_Object ticks, Lisp_Object hz,
624 *dresult = s_ns_to_double (mpz_get_d (*q), ns); 619 *dresult = s_ns_to_double (mpz_get_d (*q), ns);
625 } 620 }
626 621
627 return true; 622 return 0;
628} 623}
629 624
630/* Lisp timestamp classification. */ 625/* Lisp timestamp classification. */
@@ -649,9 +644,8 @@ enum timeform
649 start of the POSIX Epoch. Unsuccessful calls may or may not store 644 start of the POSIX Epoch. Unsuccessful calls may or may not store
650 results. 645 results.
651 646
652 Return true if successful, false if the components are of the wrong 647 Return zero if successful, an error number otherwise. */
653 type. */ 648static int
654static bool
655decode_time_components (enum timeform form, 649decode_time_components (enum timeform form,
656 Lisp_Object high, Lisp_Object low, 650 Lisp_Object high, Lisp_Object low,
657 Lisp_Object usec, Lisp_Object psec, 651 Lisp_Object usec, Lisp_Object psec,
@@ -660,7 +654,7 @@ decode_time_components (enum timeform form,
660 switch (form) 654 switch (form)
661 { 655 {
662 case TIMEFORM_INVALID: 656 case TIMEFORM_INVALID:
663 return false; 657 return EINVAL;
664 658
665 case TIMEFORM_TICKS_HZ: 659 case TIMEFORM_TICKS_HZ:
666 return decode_ticks_hz (high, low, result, dresult); 660 return decode_ticks_hz (high, low, result, dresult);
@@ -673,7 +667,7 @@ decode_time_components (enum timeform form,
673 else 667 else
674 { 668 {
675 *dresult = t; 669 *dresult = t;
676 return true; 670 return 0;
677 } 671 }
678 } 672 }
679 673
@@ -687,7 +681,7 @@ decode_time_components (enum timeform form,
687 } 681 }
688 else 682 else
689 *dresult = s_ns_to_double (now.tv_sec, now.tv_nsec); 683 *dresult = s_ns_to_double (now.tv_sec, now.tv_nsec);
690 return true; 684 return 0;
691 } 685 }
692 686
693 default: 687 default:
@@ -696,7 +690,7 @@ decode_time_components (enum timeform form,
696 690
697 if (! (INTEGERP (high) && INTEGERP (low) 691 if (! (INTEGERP (high) && INTEGERP (low)
698 && FIXNUMP (usec) && FIXNUMP (psec))) 692 && FIXNUMP (usec) && FIXNUMP (psec)))
699 return false; 693 return EINVAL;
700 EMACS_INT us = XFIXNUM (usec); 694 EMACS_INT us = XFIXNUM (usec);
701 EMACS_INT ps = XFIXNUM (psec); 695 EMACS_INT ps = XFIXNUM (psec);
702 696
@@ -740,7 +734,7 @@ decode_time_components (enum timeform form,
740 else 734 else
741 *dresult = mpz_get_d (mpz[0]) + (us * 1e6L + ps) / 1e12L; 735 *dresult = mpz_get_d (mpz[0]) + (us * 1e6L + ps) / 1e12L;
742 736
743 return true; 737 return 0;
744} 738}
745 739
746enum { DECODE_SECS_ONLY = WARN_OBSOLETE_TIMESTAMPS + 1 }; 740enum { DECODE_SECS_ONLY = WARN_OBSOLETE_TIMESTAMPS + 1 };
@@ -758,9 +752,8 @@ enum { DECODE_SECS_ONLY = WARN_OBSOLETE_TIMESTAMPS + 1 };
758 start of the POSIX Epoch. Unsuccessful calls may or may not store 752 start of the POSIX Epoch. Unsuccessful calls may or may not store
759 results. 753 results.
760 754
761 Return true if successful, false if SPECIFIED_TIME is 755 Signal an error if unsuccessful. */
762 not a valid Lisp timestamp. */ 756static void
763static bool
764decode_lisp_time (Lisp_Object specified_time, int flags, 757decode_lisp_time (Lisp_Object specified_time, int flags,
765 enum timeform *pform, 758 enum timeform *pform,
766 struct lisp_time *result, double *dresult) 759 struct lisp_time *result, double *dresult)
@@ -820,7 +813,10 @@ decode_lisp_time (Lisp_Object specified_time, int flags,
820 813
821 if (pform) 814 if (pform)
822 *pform = form; 815 *pform = form;
823 return decode_time_components (form, high, low, usec, psec, result, dresult); 816 int err = decode_time_components (form, high, low, usec, psec,
817 result, dresult);
818 if (err)
819 time_error (err);
824} 820}
825 821
826/* Convert Z to time_t, returning true if it fits. */ 822/* Convert Z to time_t, returning true if it fits. */
@@ -915,8 +911,8 @@ list4_to_timespec (Lisp_Object high, Lisp_Object low,
915 struct timespec *result) 911 struct timespec *result)
916{ 912{
917 struct lisp_time t; 913 struct lisp_time t;
918 if (! decode_time_components (TIMEFORM_HI_LO_US_PS, high, low, usec, psec, 914 if (decode_time_components (TIMEFORM_HI_LO_US_PS, high, low, usec, psec,
919 &t, 0)) 915 &t, 0))
920 return false; 916 return false;
921 *result = lisp_to_timespec (t); 917 *result = lisp_to_timespec (t);
922 return timespec_valid_p (*result); 918 return timespec_valid_p (*result);
@@ -928,10 +924,8 @@ list4_to_timespec (Lisp_Object high, Lisp_Object low,
928static struct lisp_time 924static struct lisp_time
929lisp_time_struct (Lisp_Object specified_time, enum timeform *pform) 925lisp_time_struct (Lisp_Object specified_time, enum timeform *pform)
930{ 926{
931 int flags = WARN_OBSOLETE_TIMESTAMPS;
932 struct lisp_time t; 927 struct lisp_time t;
933 if (! decode_lisp_time (specified_time, flags, pform, &t, 0)) 928 decode_lisp_time (specified_time, WARN_OBSOLETE_TIMESTAMPS, pform, &t, 0);
934 invalid_time ();
935 return t; 929 return t;
936} 930}
937 931
@@ -956,8 +950,7 @@ lisp_seconds_argument (Lisp_Object specified_time)
956{ 950{
957 int flags = WARN_OBSOLETE_TIMESTAMPS | DECODE_SECS_ONLY; 951 int flags = WARN_OBSOLETE_TIMESTAMPS | DECODE_SECS_ONLY;
958 struct lisp_time lt; 952 struct lisp_time lt;
959 if (! decode_lisp_time (specified_time, flags, 0, &lt, 0)) 953 decode_lisp_time (specified_time, flags, 0, &lt, 0);
960 invalid_time ();
961 struct timespec t = lisp_to_timespec (lt); 954 struct timespec t = lisp_to_timespec (lt);
962 if (! timespec_valid_p (t)) 955 if (! timespec_valid_p (t))
963 time_overflow (); 956 time_overflow ();
@@ -1126,8 +1119,7 @@ or (if you need time as a string) `format-time-string'. */)
1126 (Lisp_Object specified_time) 1119 (Lisp_Object specified_time)
1127{ 1120{
1128 double t; 1121 double t;
1129 if (! decode_lisp_time (specified_time, 0, 0, 0, &t)) 1122 decode_lisp_time (specified_time, 0, 0, 0, &t);
1130 invalid_time ();
1131 return make_float (t); 1123 return make_float (t);
1132} 1124}
1133 1125
@@ -1200,8 +1192,9 @@ format_time_string (char const *format, ptrdiff_t formatlen,
1200 tmp = emacs_localtime_rz (tz, &tsec, tmp); 1192 tmp = emacs_localtime_rz (tz, &tsec, tmp);
1201 if (! tmp) 1193 if (! tmp)
1202 { 1194 {
1195 int localtime_errno = errno;
1203 xtzfree (tz); 1196 xtzfree (tz);
1204 time_overflow (); 1197 time_error (localtime_errno);
1205 } 1198 }
1206 synchronize_system_time_locale (); 1199 synchronize_system_time_locale ();
1207 1200
@@ -1338,10 +1331,12 @@ usage: (decode-time &optional TIME ZONE) */)
1338 struct tm local_tm, gmt_tm; 1331 struct tm local_tm, gmt_tm;
1339 timezone_t tz = tzlookup (zone, false); 1332 timezone_t tz = tzlookup (zone, false);
1340 struct tm *tm = emacs_localtime_rz (tz, &time_spec, &local_tm); 1333 struct tm *tm = emacs_localtime_rz (tz, &time_spec, &local_tm);
1334 int localtime_errno = errno;
1341 xtzfree (tz); 1335 xtzfree (tz);
1342 1336
1343 if (! (tm 1337 if (!tm)
1344 && MOST_NEGATIVE_FIXNUM - TM_YEAR_BASE <= local_tm.tm_year 1338 time_error (localtime_errno);
1339 if (! (MOST_NEGATIVE_FIXNUM - TM_YEAR_BASE <= local_tm.tm_year
1345 && local_tm.tm_year <= MOST_POSITIVE_FIXNUM - TM_YEAR_BASE)) 1340 && local_tm.tm_year <= MOST_POSITIVE_FIXNUM - TM_YEAR_BASE))
1346 time_overflow (); 1341 time_overflow ();
1347 1342
@@ -1445,7 +1440,6 @@ year values as low as 1901 do work.
1445usage: (encode-time &optional TIME FORM &rest OBSOLESCENT-ARGUMENTS) */) 1440usage: (encode-time &optional TIME FORM &rest OBSOLESCENT-ARGUMENTS) */)
1446 (ptrdiff_t nargs, Lisp_Object *args) 1441 (ptrdiff_t nargs, Lisp_Object *args)
1447{ 1442{
1448 time_t value;
1449 struct tm tm; 1443 struct tm tm;
1450 Lisp_Object form = Qnil, zone = Qnil; 1444 Lisp_Object form = Qnil, zone = Qnil;
1451 Lisp_Object a = args[0]; 1445 Lisp_Object a = args[0];
@@ -1460,8 +1454,7 @@ usage: (encode-time &optional TIME FORM &rest OBSOLESCENT-ARGUMENTS) */)
1460 if (! CONSP (tail)) 1454 if (! CONSP (tail))
1461 { 1455 {
1462 struct lisp_time t; 1456 struct lisp_time t;
1463 if (! decode_lisp_time (a, 0, 0, &t, 0)) 1457 decode_lisp_time (a, 0, 0, &t, 0);
1464 invalid_time ();
1465 return lisp_time_form_stamp (t, form); 1458 return lisp_time_form_stamp (t, form);
1466 } 1459 }
1467 tm.tm_sec = check_tm_member (XCAR (a), 0); a = XCDR (a); 1460 tm.tm_sec = check_tm_member (XCAR (a), 0); a = XCDR (a);
@@ -1492,11 +1485,13 @@ usage: (encode-time &optional TIME FORM &rest OBSOLESCENT-ARGUMENTS) */)
1492 } 1485 }
1493 1486
1494 timezone_t tz = tzlookup (zone, false); 1487 timezone_t tz = tzlookup (zone, false);
1495 value = emacs_mktime_z (tz, &tm); 1488 tm.tm_wday = -1;
1489 time_t value = mktime_z (tz, &tm);
1490 int mktime_errno = errno;
1496 xtzfree (tz); 1491 xtzfree (tz);
1497 1492
1498 if (value == (time_t) -1) 1493 if (tm.tm_wday < 0)
1499 time_overflow (); 1494 time_error (mktime_errno);
1500 1495
1501 return time_form_stamp (value, form); 1496 return time_form_stamp (value, form);
1502} 1497}
@@ -1544,9 +1539,10 @@ without consideration for daylight saving time. */)
1544 range -999 .. 9999. */ 1539 range -999 .. 9999. */
1545 struct tm tm; 1540 struct tm tm;
1546 struct tm *tmp = emacs_localtime_rz (tz, &value, &tm); 1541 struct tm *tmp = emacs_localtime_rz (tz, &value, &tm);
1542 int localtime_errno = errno;
1547 xtzfree (tz); 1543 xtzfree (tz);
1548 if (! tmp) 1544 if (! tmp)
1549 time_overflow (); 1545 time_error (localtime_errno);
1550 1546
1551 static char const wday_name[][4] = 1547 static char const wday_name[][4] =
1552 { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; 1548 { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };