aboutsummaryrefslogtreecommitdiffstats
path: root/src/editfns.c
diff options
context:
space:
mode:
authorPaul Eggert2011-03-11 22:49:53 -0800
committerPaul Eggert2011-03-11 22:49:53 -0800
commitb8d9bd41b7daaa35de8335b20af145a808ae9b07 (patch)
treebb00176e7801612ad1de68713f9128446bc9751d /src/editfns.c
parentfe31d94c97a6a3702e301a14b84c1f293afe5efd (diff)
downloademacs-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/editfns.c')
-rw-r--r--src/editfns.c99
1 files changed, 71 insertions, 28 deletions
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. */
1430static void
1431time_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. */
1438static EMACS_INT
1439hi_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. */
1452static EMACS_INT
1453lo_time (time_t t)
1454{
1455 return t & ((1 << 16) - 1);
1456}
1457
1418DEFUN ("current-time", Fcurrent_time, Scurrent_time, 0, 0, 0, 1458DEFUN ("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.
1420The time is returned as a list of three integers. The first has the 1460The 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. */
1481static void
1482time_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. */
1488Lisp_Object 1522Lisp_Object
1489make_time (time_t t) 1523make_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. */
1820static int
1821check_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
1781DEFUN ("encode-time", Fencode_time, Sencode_time, 6, MANY, 0, 1831DEFUN ("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.
1783This is the reverse operation of `decode-time', which see. 1833This 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))