diff options
| author | Paul Eggert | 2011-03-11 22:49:53 -0800 |
|---|---|---|
| committer | Paul Eggert | 2011-03-11 22:49:53 -0800 |
| commit | b8d9bd41b7daaa35de8335b20af145a808ae9b07 (patch) | |
| tree | bb00176e7801612ad1de68713f9128446bc9751d /src | |
| parent | fe31d94c97a6a3702e301a14b84c1f293afe5efd (diff) | |
| download | emacs-b8d9bd41b7daaa35de8335b20af145a808ae9b07.tar.gz emacs-b8d9bd41b7daaa35de8335b20af145a808ae9b07.zip | |
Improve quality of tests for time stamp overflow. For example,
without this patch (encode-time 0 0 0 1 1 1152921504606846976)
returns the obviously-bogus value (-948597 62170) on my RHEL 5.5
x86-64 host. With it, it reports time overflow.
* deps.mk (editfns.o): Depend on ../lib/intprops.h.
* editfns.c: Include limits.h and intprops.h.
(TIME_T_MIN, TIME_T_MAX): New macros.
(time_overflow): Move earlier, to before first use.
(hi_time, lo_time): New functions, for an accurate test for
out-of-range times.
(Fcurrent_time, Fget_internal_run_time, make_time): Use them.
(Fget_internal_run_time): Don't assume time_t fits in int.
(make_time): Use list2 instead of Fcons twice.
(Fdecode_time): More accurate test for out-of-range times.
(check_tm_member): New function.
(Fencode_time): Use it, to test for out-of-range times.
Diffstat (limited to 'src')
| -rw-r--r-- | src/ChangeLog | 19 | ||||
| -rw-r--r-- | src/deps.mk | 3 | ||||
| -rw-r--r-- | src/editfns.c | 99 |
3 files changed, 92 insertions, 29 deletions
diff --git a/src/ChangeLog b/src/ChangeLog index a0c4941ec1c..b3362b9fbca 100644 --- a/src/ChangeLog +++ b/src/ChangeLog | |||
| @@ -1,3 +1,22 @@ | |||
| 1 | 2011-03-12 Paul Eggert <eggert@cs.ucla.edu> | ||
| 2 | |||
| 3 | Improve quality of tests for time stamp overflow. For example, | ||
| 4 | without this patch (encode-time 0 0 0 1 1 1152921504606846976) | ||
| 5 | returns the obviously-bogus value (-948597 62170) on my RHEL 5.5 | ||
| 6 | x86-64 host. With it, it reports time overflow. | ||
| 7 | * deps.mk (editfns.o): Depend on ../lib/intprops.h. | ||
| 8 | * editfns.c: Include limits.h and intprops.h. | ||
| 9 | (TIME_T_MIN, TIME_T_MAX): New macros. | ||
| 10 | (time_overflow): Move earlier, to before first use. | ||
| 11 | (hi_time, lo_time): New functions, for an accurate test for | ||
| 12 | out-of-range times. | ||
| 13 | (Fcurrent_time, Fget_internal_run_time, make_time): Use them. | ||
| 14 | (Fget_internal_run_time): Don't assume time_t fits in int. | ||
| 15 | (make_time): Use list2 instead of Fcons twice. | ||
| 16 | (Fdecode_time): More accurate test for out-of-range times. | ||
| 17 | (check_tm_member): New function. | ||
| 18 | (Fencode_time): Use it, to test for out-of-range times. | ||
| 19 | |||
| 1 | 2011-03-11 Paul Eggert <eggert@cs.ucla.edu> | 20 | 2011-03-11 Paul Eggert <eggert@cs.ucla.edu> |
| 2 | 21 | ||
| 3 | * editfns.c (time_overflow): New function, refactoring common code. | 22 | * editfns.c (time_overflow): New function, refactoring common code. |
diff --git a/src/deps.mk b/src/deps.mk index 2b162b07bb8..fba856c1be3 100644 --- a/src/deps.mk +++ b/src/deps.mk | |||
| @@ -87,7 +87,8 @@ dosfns.o: buffer.h termchar.h termhooks.h frame.h blockinput.h window.h \ | |||
| 87 | msdos.h dosfns.h dispextern.h charset.h coding.h atimer.h systime.h \ | 87 | msdos.h dosfns.h dispextern.h charset.h coding.h atimer.h systime.h \ |
| 88 | lisp.h $(config_h) | 88 | lisp.h $(config_h) |
| 89 | editfns.o: editfns.c window.h buffer.h systime.h $(INTERVALS_H) character.h \ | 89 | editfns.o: editfns.c window.h buffer.h systime.h $(INTERVALS_H) character.h \ |
| 90 | coding.h frame.h blockinput.h atimer.h ../lib/unistd.h ../lib/strftime.h \ | 90 | coding.h frame.h blockinput.h atimer.h \ |
| 91 | ../lib/intprops.h ../lib/strftime.h ../lib/unistd.h \ | ||
| 91 | lisp.h globals.h $(config_h) | 92 | lisp.h globals.h $(config_h) |
| 92 | emacs.o: emacs.c commands.h systty.h syssignal.h blockinput.h process.h \ | 93 | emacs.o: emacs.c commands.h systty.h syssignal.h blockinput.h process.h \ |
| 93 | termhooks.h buffer.h atimer.h systime.h $(INTERVALS_H) lisp.h $(config_h) \ | 94 | termhooks.h buffer.h atimer.h systime.h $(INTERVALS_H) lisp.h $(config_h) \ |
diff --git a/src/editfns.c b/src/editfns.c index fe8541f718e..4e8ac316a8a 100644 --- a/src/editfns.c +++ b/src/editfns.c | |||
| @@ -45,6 +45,8 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ | |||
| 45 | #endif | 45 | #endif |
| 46 | 46 | ||
| 47 | #include <ctype.h> | 47 | #include <ctype.h> |
| 48 | #include <limits.h> | ||
| 49 | #include <intprops.h> | ||
| 48 | #include <strftime.h> | 50 | #include <strftime.h> |
| 49 | 51 | ||
| 50 | #include "intervals.h" | 52 | #include "intervals.h" |
| @@ -1415,6 +1417,44 @@ DEFUN ("emacs-pid", Femacs_pid, Semacs_pid, 0, 0, 0, | |||
| 1415 | return make_number (getpid ()); | 1417 | return make_number (getpid ()); |
| 1416 | } | 1418 | } |
| 1417 | 1419 | ||
| 1420 | |||
| 1421 | |||
| 1422 | #ifndef TIME_T_MIN | ||
| 1423 | # define TIME_T_MIN TYPE_MINIMUM (time_t) | ||
| 1424 | #endif | ||
| 1425 | #ifndef TIME_T_MAX | ||
| 1426 | # define TIME_T_MAX TYPE_MAXIMUM (time_t) | ||
| 1427 | #endif | ||
| 1428 | |||
| 1429 | /* Report that a time value is out of range for Emacs. */ | ||
| 1430 | static void | ||
| 1431 | time_overflow (void) | ||
| 1432 | { | ||
| 1433 | error ("Specified time is not representable"); | ||
| 1434 | } | ||
| 1435 | |||
| 1436 | /* Return the upper part of the time T (everything but the bottom 16 bits), | ||
| 1437 | making sure that it is representable. */ | ||
| 1438 | static EMACS_INT | ||
| 1439 | hi_time (time_t t) | ||
| 1440 | { | ||
| 1441 | time_t hi = t >> 16; | ||
| 1442 | if (((TYPE_SIGNED (time_t) | ||
| 1443 | && TIME_T_MIN >> 16 < MOST_NEGATIVE_FIXNUM | ||
| 1444 | && hi < MOST_NEGATIVE_FIXNUM) | ||
| 1445 | || (MOST_POSITIVE_FIXNUM < TIME_T_MAX >> 16 | ||
| 1446 | && MOST_POSITIVE_FIXNUM < hi))) | ||
| 1447 | time_overflow (); | ||
| 1448 | return hi; | ||
| 1449 | } | ||
| 1450 | |||
| 1451 | /* Return the bottom 16 bits of the time T. */ | ||
| 1452 | static EMACS_INT | ||
| 1453 | lo_time (time_t t) | ||
| 1454 | { | ||
| 1455 | return t & ((1 << 16) - 1); | ||
| 1456 | } | ||
| 1457 | |||
| 1418 | DEFUN ("current-time", Fcurrent_time, Scurrent_time, 0, 0, 0, | 1458 | DEFUN ("current-time", Fcurrent_time, Scurrent_time, 0, 0, 0, |
| 1419 | doc: /* Return the current time, as the number of seconds since 1970-01-01 00:00:00. | 1459 | doc: /* Return the current time, as the number of seconds since 1970-01-01 00:00:00. |
| 1420 | The time is returned as a list of three integers. The first has the | 1460 | The time is returned as a list of three integers. The first has the |
| @@ -1429,8 +1469,8 @@ resolution finer than a second. */) | |||
| 1429 | EMACS_TIME t; | 1469 | EMACS_TIME t; |
| 1430 | 1470 | ||
| 1431 | EMACS_GET_TIME (t); | 1471 | EMACS_GET_TIME (t); |
| 1432 | return list3 (make_number ((EMACS_SECS (t) >> 16) & 0xffff), | 1472 | return list3 (make_number (hi_time (EMACS_SECS (t))), |
| 1433 | make_number ((EMACS_SECS (t) >> 0) & 0xffff), | 1473 | make_number (lo_time (EMACS_SECS (t))), |
| 1434 | make_number (EMACS_USECS (t))); | 1474 | make_number (EMACS_USECS (t))); |
| 1435 | } | 1475 | } |
| 1436 | 1476 | ||
| @@ -1449,7 +1489,8 @@ on systems that do not provide resolution finer than a second. */) | |||
| 1449 | { | 1489 | { |
| 1450 | #ifdef HAVE_GETRUSAGE | 1490 | #ifdef HAVE_GETRUSAGE |
| 1451 | struct rusage usage; | 1491 | struct rusage usage; |
| 1452 | int secs, usecs; | 1492 | time_t secs; |
| 1493 | int usecs; | ||
| 1453 | 1494 | ||
| 1454 | if (getrusage (RUSAGE_SELF, &usage) < 0) | 1495 | if (getrusage (RUSAGE_SELF, &usage) < 0) |
| 1455 | /* This shouldn't happen. What action is appropriate? */ | 1496 | /* This shouldn't happen. What action is appropriate? */ |
| @@ -1464,8 +1505,8 @@ on systems that do not provide resolution finer than a second. */) | |||
| 1464 | secs++; | 1505 | secs++; |
| 1465 | } | 1506 | } |
| 1466 | 1507 | ||
| 1467 | return list3 (make_number ((secs >> 16) & 0xffff), | 1508 | return list3 (make_number (hi_time (secs)), |
| 1468 | make_number ((secs >> 0) & 0xffff), | 1509 | make_number (lo_time (secs)), |
| 1469 | make_number (usecs)); | 1510 | make_number (usecs)); |
| 1470 | #else /* ! HAVE_GETRUSAGE */ | 1511 | #else /* ! HAVE_GETRUSAGE */ |
| 1471 | #ifdef WINDOWSNT | 1512 | #ifdef WINDOWSNT |
| @@ -1477,19 +1518,12 @@ on systems that do not provide resolution finer than a second. */) | |||
| 1477 | } | 1518 | } |
| 1478 | 1519 | ||
| 1479 | 1520 | ||
| 1480 | /* Report a time value that is out of range for Emacs. */ | ||
| 1481 | static void | ||
| 1482 | time_overflow (void) | ||
| 1483 | { | ||
| 1484 | error ("Specified time is not representable"); | ||
| 1485 | } | ||
| 1486 | |||
| 1487 | /* Make a Lisp list that represents the time T. */ | 1521 | /* Make a Lisp list that represents the time T. */ |
| 1488 | Lisp_Object | 1522 | Lisp_Object |
| 1489 | make_time (time_t t) | 1523 | make_time (time_t t) |
| 1490 | { | 1524 | { |
| 1491 | return Fcons (make_number (t >> 16), | 1525 | return list2 (make_number (hi_time (t)), |
| 1492 | Fcons (make_number (t & 0177777), Qnil)); | 1526 | make_number (lo_time (t))); |
| 1493 | } | 1527 | } |
| 1494 | 1528 | ||
| 1495 | /* Decode a Lisp list SPECIFIED_TIME that represents a time. | 1529 | /* Decode a Lisp list SPECIFIED_TIME that represents a time. |
| @@ -1753,7 +1787,9 @@ DOW and ZONE.) */) | |||
| 1753 | BLOCK_INPUT; | 1787 | BLOCK_INPUT; |
| 1754 | decoded_time = localtime (&time_spec); | 1788 | decoded_time = localtime (&time_spec); |
| 1755 | UNBLOCK_INPUT; | 1789 | UNBLOCK_INPUT; |
| 1756 | if (! decoded_time) | 1790 | if (! (decoded_time |
| 1791 | && MOST_NEGATIVE_FIXNUM - TM_YEAR_BASE <= decoded_time->tm_year | ||
| 1792 | && decoded_time->tm_year <= MOST_POSITIVE_FIXNUM - TM_YEAR_BASE)) | ||
| 1757 | time_overflow (); | 1793 | time_overflow (); |
| 1758 | XSETFASTINT (list_args[0], decoded_time->tm_sec); | 1794 | XSETFASTINT (list_args[0], decoded_time->tm_sec); |
| 1759 | XSETFASTINT (list_args[1], decoded_time->tm_min); | 1795 | XSETFASTINT (list_args[1], decoded_time->tm_min); |
| @@ -1778,6 +1814,20 @@ DOW and ZONE.) */) | |||
| 1778 | return Flist (9, list_args); | 1814 | return Flist (9, list_args); |
| 1779 | } | 1815 | } |
| 1780 | 1816 | ||
| 1817 | /* Return OBJ - OFFSET, checking that OBJ is a valid fixnum and that | ||
| 1818 | the result is representable as an int. Assume OFFSET is small and | ||
| 1819 | nonnegative. */ | ||
| 1820 | static int | ||
| 1821 | check_tm_member (Lisp_Object obj, int offset) | ||
| 1822 | { | ||
| 1823 | EMACS_INT n; | ||
| 1824 | CHECK_NUMBER (obj); | ||
| 1825 | n = XINT (obj); | ||
| 1826 | if (! (INT_MIN + offset <= n && n - offset <= INT_MAX)) | ||
| 1827 | time_overflow (); | ||
| 1828 | return n - offset; | ||
| 1829 | } | ||
| 1830 | |||
| 1781 | DEFUN ("encode-time", Fencode_time, Sencode_time, 6, MANY, 0, | 1831 | DEFUN ("encode-time", Fencode_time, Sencode_time, 6, MANY, 0, |
| 1782 | doc: /* Convert SECOND, MINUTE, HOUR, DAY, MONTH, YEAR and ZONE to internal time. | 1832 | doc: /* Convert SECOND, MINUTE, HOUR, DAY, MONTH, YEAR and ZONE to internal time. |
| 1783 | This is the reverse operation of `decode-time', which see. | 1833 | This is the reverse operation of `decode-time', which see. |
| @@ -1806,19 +1856,12 @@ usage: (encode-time SECOND MINUTE HOUR DAY MONTH YEAR &optional ZONE) */) | |||
| 1806 | struct tm tm; | 1856 | struct tm tm; |
| 1807 | Lisp_Object zone = (nargs > 6 ? args[nargs - 1] : Qnil); | 1857 | Lisp_Object zone = (nargs > 6 ? args[nargs - 1] : Qnil); |
| 1808 | 1858 | ||
| 1809 | CHECK_NUMBER (args[0]); /* second */ | 1859 | tm.tm_sec = check_tm_member (args[0], 0); |
| 1810 | CHECK_NUMBER (args[1]); /* minute */ | 1860 | tm.tm_min = check_tm_member (args[1], 0); |
| 1811 | CHECK_NUMBER (args[2]); /* hour */ | 1861 | tm.tm_hour = check_tm_member (args[2], 0); |
| 1812 | CHECK_NUMBER (args[3]); /* day */ | 1862 | tm.tm_mday = check_tm_member (args[3], 0); |
| 1813 | CHECK_NUMBER (args[4]); /* month */ | 1863 | tm.tm_mon = check_tm_member (args[4], 1); |
| 1814 | CHECK_NUMBER (args[5]); /* year */ | 1864 | tm.tm_year = check_tm_member (args[5], TM_YEAR_BASE); |
| 1815 | |||
| 1816 | tm.tm_sec = XINT (args[0]); | ||
| 1817 | tm.tm_min = XINT (args[1]); | ||
| 1818 | tm.tm_hour = XINT (args[2]); | ||
| 1819 | tm.tm_mday = XINT (args[3]); | ||
| 1820 | tm.tm_mon = XINT (args[4]) - 1; | ||
| 1821 | tm.tm_year = XINT (args[5]) - TM_YEAR_BASE; | ||
| 1822 | tm.tm_isdst = -1; | 1865 | tm.tm_isdst = -1; |
| 1823 | 1866 | ||
| 1824 | if (CONSP (zone)) | 1867 | if (CONSP (zone)) |