diff options
| author | Paul Eggert | 2018-11-03 13:11:26 -0700 |
|---|---|---|
| committer | Paul Eggert | 2018-11-03 21:36:46 -0700 |
| commit | b4eb908f858284a7962851fd99c94598f76afa6f (patch) | |
| tree | d4e91b37d685ec7491c34e76598a0d3b3429cf34 /src | |
| parent | 07048183a86134b63cb7132038fab6f36a1e57ca (diff) | |
| download | emacs-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.c | 102 |
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 | ||
| 174 | static time_t | ||
| 175 | emacs_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 | |||
| 184 | static _Noreturn void | 174 | static _Noreturn void |
| 185 | invalid_time_zone_specification (Lisp_Object zone) | 175 | invalid_time_zone_specification (Lisp_Object zone) |
| 186 | { | 176 | { |
| @@ -347,9 +337,14 @@ time_overflow (void) | |||
| 347 | } | 337 | } |
| 348 | 338 | ||
| 349 | static _Noreturn void | 339 | static _Noreturn void |
| 350 | invalid_time (void) | 340 | time_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 | ||
| 355 | static _Noreturn void | 350 | static _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. */ |
| 377 | static bool | 372 | static int |
| 378 | decode_float_time (double t, struct lisp_time *result) | 373 | decode_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. */ |
| 574 | static bool | 569 | static int |
| 575 | decode_ticks_hz (Lisp_Object ticks, Lisp_Object hz, | 570 | decode_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. */ | 648 | static int |
| 654 | static bool | ||
| 655 | decode_time_components (enum timeform form, | 649 | decode_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 | ||
| 746 | enum { DECODE_SECS_ONLY = WARN_OBSOLETE_TIMESTAMPS + 1 }; | 740 | enum { 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. */ | 756 | static void |
| 763 | static bool | ||
| 764 | decode_lisp_time (Lisp_Object specified_time, int flags, | 757 | decode_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, | |||
| 928 | static struct lisp_time | 924 | static struct lisp_time |
| 929 | lisp_time_struct (Lisp_Object specified_time, enum timeform *pform) | 925 | lisp_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, <, 0)) | 953 | decode_lisp_time (specified_time, flags, 0, <, 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. | |||
| 1445 | usage: (encode-time &optional TIME FORM &rest OBSOLESCENT-ARGUMENTS) */) | 1440 | usage: (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" }; |