diff options
| author | Paul Eggert | 2018-09-04 19:14:01 -0700 |
|---|---|---|
| committer | Paul Eggert | 2018-09-04 19:15:57 -0700 |
| commit | ccb3891ff5446b578b9306aec0fd9c5ec3ed8e98 (patch) | |
| tree | 888bda0e0584ef78d2a3b25cc6c03b35b6b8ea8e | |
| parent | ecb985c10d5241a65ab9552ebfcecaa150b35427 (diff) | |
| download | emacs-ccb3891ff5446b578b9306aec0fd9c5ec3ed8e98.tar.gz emacs-ccb3891ff5446b578b9306aec0fd9c5ec3ed8e98.zip | |
Fix format-time-string bignum bug
The problem can occur on 32-bit platforms with current timestamps.
* src/editfns.c (disassemble_lisp_time, decode_time_components):
Support seconds counts that are bignums.
* test/src/editfns-tests.el (editfns-tests--have-leap-seconds):
New function.
(format-time-string-with-bignum-on-32-bit): New test.
| -rw-r--r-- | src/editfns.c | 15 | ||||
| -rw-r--r-- | test/src/editfns-tests.el | 10 |
2 files changed, 19 insertions, 6 deletions
diff --git a/src/editfns.c b/src/editfns.c index 4ea70253793..191a9ab8f8a 100644 --- a/src/editfns.c +++ b/src/editfns.c | |||
| @@ -1743,10 +1743,10 @@ disassemble_lisp_time (Lisp_Object specified_time, Lisp_Object *phigh, | |||
| 1743 | 1743 | ||
| 1744 | /* When combining components, require LOW to be an integer, | 1744 | /* When combining components, require LOW to be an integer, |
| 1745 | as otherwise it would be a pain to add up times. */ | 1745 | as otherwise it would be a pain to add up times. */ |
| 1746 | if (! FIXNUMP (low)) | 1746 | if (! INTEGERP (low)) |
| 1747 | return 0; | 1747 | return 0; |
| 1748 | } | 1748 | } |
| 1749 | else if (FIXNUMP (specified_time)) | 1749 | else if (INTEGERP (specified_time)) |
| 1750 | len = 2; | 1750 | len = 2; |
| 1751 | 1751 | ||
| 1752 | *phigh = high; | 1752 | *phigh = high; |
| @@ -1807,11 +1807,12 @@ decode_time_components (Lisp_Object high, Lisp_Object low, Lisp_Object usec, | |||
| 1807 | Lisp_Object psec, | 1807 | Lisp_Object psec, |
| 1808 | struct lisp_time *result, double *dresult) | 1808 | struct lisp_time *result, double *dresult) |
| 1809 | { | 1809 | { |
| 1810 | EMACS_INT hi, lo, us, ps; | 1810 | EMACS_INT hi, us, ps; |
| 1811 | intmax_t lo; | ||
| 1811 | if (! (FIXNUMP (high) | 1812 | if (! (FIXNUMP (high) |
| 1812 | && FIXNUMP (usec) && FIXNUMP (psec))) | 1813 | && FIXNUMP (usec) && FIXNUMP (psec))) |
| 1813 | return 0; | 1814 | return 0; |
| 1814 | if (! FIXNUMP (low)) | 1815 | if (! INTEGERP (low)) |
| 1815 | { | 1816 | { |
| 1816 | if (FLOATP (low)) | 1817 | if (FLOATP (low)) |
| 1817 | { | 1818 | { |
| @@ -1841,7 +1842,8 @@ decode_time_components (Lisp_Object high, Lisp_Object low, Lisp_Object usec, | |||
| 1841 | } | 1842 | } |
| 1842 | 1843 | ||
| 1843 | hi = XFIXNUM (high); | 1844 | hi = XFIXNUM (high); |
| 1844 | lo = XFIXNUM (low); | 1845 | if (! integer_to_intmax (low, &lo)) |
| 1846 | return -1; | ||
| 1845 | us = XFIXNUM (usec); | 1847 | us = XFIXNUM (usec); |
| 1846 | ps = XFIXNUM (psec); | 1848 | ps = XFIXNUM (psec); |
| 1847 | 1849 | ||
| @@ -1849,7 +1851,8 @@ decode_time_components (Lisp_Object high, Lisp_Object low, Lisp_Object usec, | |||
| 1849 | each overflow into the next higher-order component. */ | 1851 | each overflow into the next higher-order component. */ |
| 1850 | us += ps / 1000000 - (ps % 1000000 < 0); | 1852 | us += ps / 1000000 - (ps % 1000000 < 0); |
| 1851 | lo += us / 1000000 - (us % 1000000 < 0); | 1853 | lo += us / 1000000 - (us % 1000000 < 0); |
| 1852 | hi += lo >> LO_TIME_BITS; | 1854 | if (INT_ADD_WRAPV (lo >> LO_TIME_BITS, hi, &hi)) |
| 1855 | return -1; | ||
| 1853 | ps = ps % 1000000 + 1000000 * (ps % 1000000 < 0); | 1856 | ps = ps % 1000000 + 1000000 * (ps % 1000000 < 0); |
| 1854 | us = us % 1000000 + 1000000 * (us % 1000000 < 0); | 1857 | us = us % 1000000 + 1000000 * (us % 1000000 < 0); |
| 1855 | lo &= (1 << LO_TIME_BITS) - 1; | 1858 | lo &= (1 << LO_TIME_BITS) - 1; |
diff --git a/test/src/editfns-tests.el b/test/src/editfns-tests.el index 487f3aaa666..4a840c8d7d1 100644 --- a/test/src/editfns-tests.el +++ b/test/src/editfns-tests.el | |||
| @@ -253,6 +253,16 @@ | |||
| 253 | (format-time-string "%Y-%m-%d %H:%M:%S.%3N %z" nil | 253 | (format-time-string "%Y-%m-%d %H:%M:%S.%3N %z" nil |
| 254 | (concat (make-string 2048 ?X) "0"))))) | 254 | (concat (make-string 2048 ?X) "0"))))) |
| 255 | 255 | ||
| 256 | (defun editfns-tests--have-leap-seconds () | ||
| 257 | (string-equal (format-time-string "%Y-%m-%d %H:%M:%S" 78796800 t) | ||
| 258 | "1972-06-30 23:59:60")) | ||
| 259 | |||
| 260 | (ert-deftest format-time-string-with-bignum-on-32-bit () | ||
| 261 | (should (or (string-equal | ||
| 262 | (format-time-string "%Y-%m-%d %H:%M:%S" (- (ash 1 31) 3600) t) | ||
| 263 | "2038-01-19 02:14:08") | ||
| 264 | (editfns-tests--have-leap-seconds)))) | ||
| 265 | |||
| 256 | (ert-deftest format-with-field () | 266 | (ert-deftest format-with-field () |
| 257 | (should (equal (format "First argument %2$s, then %3$s, then %1$s" 1 2 3) | 267 | (should (equal (format "First argument %2$s, then %3$s, then %1$s" 1 2 3) |
| 258 | "First argument 2, then 3, then 1")) | 268 | "First argument 2, then 3, then 1")) |