aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPaul Eggert2011-03-12 22:43:00 -0800
committerPaul Eggert2011-03-12 22:43:00 -0800
commitd32df629a23d0e04eb70df9c6e60e821d905c822 (patch)
tree6eca6f59412dc798b055e5dec45188f5e7f3929a /src
parent4248cca2de96a6732a233e9c1d13c6336b215705 (diff)
parent313c1e544ab88d0ca95015b30e23dfbabe36a2ac (diff)
downloademacs-d32df629a23d0e04eb70df9c6e60e821d905c822.tar.gz
emacs-d32df629a23d0e04eb70df9c6e60e821d905c822.zip
Improve quality of tests for time stamp overflow.
Diffstat (limited to 'src')
-rw-r--r--src/ChangeLog32
-rw-r--r--src/deps.mk3
-rw-r--r--src/dired.c7
-rw-r--r--src/editfns.c133
-rw-r--r--src/systime.h5
5 files changed, 143 insertions, 37 deletions
diff --git a/src/ChangeLog b/src/ChangeLog
index a3098114388..1bc1e113846 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,35 @@
12011-03-13 Paul Eggert <eggert@cs.ucla.edu>
2
3 Improve quality of tests for time stamp overflow.
4 For example, without this patch (encode-time 0 0 0 1 1
5 1152921504606846976) returns the obviously-bogus value (-948597
6 62170) on my RHEL 5.5 x86-64 host. With the patch, it correctly
7 reports time overflow. See
8 <http://lists.gnu.org/archive/html/emacs-devel/2011-03/msg00470.html>.
9 * deps.mk (editfns.o): Depend on ../lib/intprops.h.
10 * editfns.c: Include limits.h and intprops.h.
11 (TIME_T_MIN, TIME_T_MAX): New macros.
12 (time_overflow): Move earlier, to before first use.
13 (hi_time, lo_time): New functions, for an accurate test for
14 out-of-range times.
15 (Fcurrent_time, Fget_internal_run_time, make_time): Use them.
16 (Fget_internal_run_time): Don't assume time_t fits in int.
17 (make_time): Use list2 instead of Fcons twice.
18 (Fdecode_time): More accurate test for out-of-range times.
19 (check_tm_member): New function.
20 (Fencode_time): Use it, to test for out-of-range times.
21 (lisp_time_argument): Don't rely on undefined left-shift and
22 right-shift behavior when checking for time stamp overflow.
23
24 * editfns.c (time_overflow): New function, refactoring common code.
25 (Fformat_time_string, Fdecode_time, Fencode_time):
26 (Fcurrent_time_string): Use it.
27
28 Move 'make_time' to be next to its inverse 'lisp_time_argument'.
29 * dired.c (make_time): Move to ...
30 * editfns.c (make_time): ... here.
31 * systime.h: Note the move.
32
12011-03-12 YAMAMOTO Mitsuharu <mituharu@math.s.chiba-u.ac.jp> 332011-03-12 YAMAMOTO Mitsuharu <mituharu@math.s.chiba-u.ac.jp>
2 34
3 * fringe.c (update_window_fringes): Remove unused variables. 35 * fringe.c (update_window_fringes): Remove unused variables.
diff --git a/src/deps.mk b/src/deps.mk
index d3a21cfe628..80a5721cf39 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)
89editfns.o: editfns.c window.h buffer.h systime.h $(INTERVALS_H) character.h \ 89editfns.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)
92emacs.o: emacs.c commands.h systty.h syssignal.h blockinput.h process.h \ 93emacs.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/dired.c b/src/dired.c
index 96063680d4d..d201418d78b 100644
--- a/src/dired.c
+++ b/src/dired.c
@@ -848,13 +848,6 @@ file_name_completion_stat (Lisp_Object dirname, DIRENTRY *dp, struct stat *st_ad
848 return value; 848 return value;
849} 849}
850 850
851Lisp_Object
852make_time (time_t time)
853{
854 return Fcons (make_number (time >> 16),
855 Fcons (make_number (time & 0177777), Qnil));
856}
857
858static char * 851static char *
859stat_uname (struct stat *st) 852stat_uname (struct stat *st)
860{ 853{
diff --git a/src/editfns.c b/src/editfns.c
index 28690e7c76d..d92d3482d09 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"
@@ -87,6 +89,7 @@ extern char **environ;
87extern Lisp_Object w32_get_internal_run_time (void); 89extern Lisp_Object w32_get_internal_run_time (void);
88#endif 90#endif
89 91
92static void time_overflow (void) NO_RETURN;
90static int tm_diff (struct tm *, struct tm *); 93static int tm_diff (struct tm *, struct tm *);
91static void find_field (Lisp_Object, Lisp_Object, Lisp_Object, 94static void find_field (Lisp_Object, Lisp_Object, Lisp_Object,
92 EMACS_INT *, Lisp_Object, EMACS_INT *); 95 EMACS_INT *, Lisp_Object, EMACS_INT *);
@@ -1414,6 +1417,49 @@ DEFUN ("emacs-pid", Femacs_pid, Semacs_pid, 0, 0, 0,
1414 return make_number (getpid ()); 1417 return make_number (getpid ());
1415} 1418}
1416 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
1443 /* Check for overflow, helping the compiler for common cases where
1444 no runtime check is needed, and taking care not to convert
1445 negative numbers to unsigned before comparing them. */
1446 if (! ((! TYPE_SIGNED (time_t)
1447 || MOST_NEGATIVE_FIXNUM <= TIME_T_MIN >> 16
1448 || MOST_NEGATIVE_FIXNUM <= hi)
1449 && (TIME_T_MAX >> 16 <= MOST_POSITIVE_FIXNUM
1450 || hi <= MOST_POSITIVE_FIXNUM)))
1451 time_overflow ();
1452
1453 return hi;
1454}
1455
1456/* Return the bottom 16 bits of the time T. */
1457static EMACS_INT
1458lo_time (time_t t)
1459{
1460 return t & ((1 << 16) - 1);
1461}
1462
1417DEFUN ("current-time", Fcurrent_time, Scurrent_time, 0, 0, 0, 1463DEFUN ("current-time", Fcurrent_time, Scurrent_time, 0, 0, 0,
1418 doc: /* Return the current time, as the number of seconds since 1970-01-01 00:00:00. 1464 doc: /* Return the current time, as the number of seconds since 1970-01-01 00:00:00.
1419The time is returned as a list of three integers. The first has the 1465The time is returned as a list of three integers. The first has the
@@ -1428,8 +1474,8 @@ resolution finer than a second. */)
1428 EMACS_TIME t; 1474 EMACS_TIME t;
1429 1475
1430 EMACS_GET_TIME (t); 1476 EMACS_GET_TIME (t);
1431 return list3 (make_number ((EMACS_SECS (t) >> 16) & 0xffff), 1477 return list3 (make_number (hi_time (EMACS_SECS (t))),
1432 make_number ((EMACS_SECS (t) >> 0) & 0xffff), 1478 make_number (lo_time (EMACS_SECS (t))),
1433 make_number (EMACS_USECS (t))); 1479 make_number (EMACS_USECS (t)));
1434} 1480}
1435 1481
@@ -1448,7 +1494,8 @@ on systems that do not provide resolution finer than a second. */)
1448{ 1494{
1449#ifdef HAVE_GETRUSAGE 1495#ifdef HAVE_GETRUSAGE
1450 struct rusage usage; 1496 struct rusage usage;
1451 int secs, usecs; 1497 time_t secs;
1498 int usecs;
1452 1499
1453 if (getrusage (RUSAGE_SELF, &usage) < 0) 1500 if (getrusage (RUSAGE_SELF, &usage) < 0)
1454 /* This shouldn't happen. What action is appropriate? */ 1501 /* This shouldn't happen. What action is appropriate? */
@@ -1463,8 +1510,8 @@ on systems that do not provide resolution finer than a second. */)
1463 secs++; 1510 secs++;
1464 } 1511 }
1465 1512
1466 return list3 (make_number ((secs >> 16) & 0xffff), 1513 return list3 (make_number (hi_time (secs)),
1467 make_number ((secs >> 0) & 0xffff), 1514 make_number (lo_time (secs)),
1468 make_number (usecs)); 1515 make_number (usecs));
1469#else /* ! HAVE_GETRUSAGE */ 1516#else /* ! HAVE_GETRUSAGE */
1470#ifdef WINDOWSNT 1517#ifdef WINDOWSNT
@@ -1476,6 +1523,19 @@ on systems that do not provide resolution finer than a second. */)
1476} 1523}
1477 1524
1478 1525
1526/* Make a Lisp list that represents the time T. */
1527Lisp_Object
1528make_time (time_t t)
1529{
1530 return list2 (make_number (hi_time (t)),
1531 make_number (lo_time (t)));
1532}
1533
1534/* Decode a Lisp list SPECIFIED_TIME that represents a time.
1535 If SPECIFIED_TIME is nil, use the current time.
1536 Set *RESULT to seconds since the Epoch.
1537 If USEC is not null, set *USEC to the microseconds component.
1538 Return nonzero if successful. */
1479int 1539int
1480lisp_time_argument (Lisp_Object specified_time, time_t *result, int *usec) 1540lisp_time_argument (Lisp_Object specified_time, time_t *result, int *usec)
1481{ 1541{
@@ -1496,6 +1556,7 @@ lisp_time_argument (Lisp_Object specified_time, time_t *result, int *usec)
1496 else 1556 else
1497 { 1557 {
1498 Lisp_Object high, low; 1558 Lisp_Object high, low;
1559 EMACS_INT hi;
1499 high = Fcar (specified_time); 1560 high = Fcar (specified_time);
1500 CHECK_NUMBER (high); 1561 CHECK_NUMBER (high);
1501 low = Fcdr (specified_time); 1562 low = Fcdr (specified_time);
@@ -1519,8 +1580,21 @@ lisp_time_argument (Lisp_Object specified_time, time_t *result, int *usec)
1519 else if (usec) 1580 else if (usec)
1520 *usec = 0; 1581 *usec = 0;
1521 CHECK_NUMBER (low); 1582 CHECK_NUMBER (low);
1522 *result = (XINT (high) << 16) + (XINT (low) & 0xffff); 1583 hi = XINT (high);
1523 return *result >> 16 == XINT (high); 1584
1585 /* Check for overflow, helping the compiler for common cases
1586 where no runtime check is needed, and taking care not to
1587 convert negative numbers to unsigned before comparing them. */
1588 if (! ((TYPE_SIGNED (time_t)
1589 ? (TIME_T_MIN >> 16 <= MOST_NEGATIVE_FIXNUM
1590 || TIME_T_MIN >> 16 <= hi)
1591 : 0 <= hi)
1592 && (MOST_POSITIVE_FIXNUM <= TIME_T_MAX >> 16
1593 || hi <= TIME_T_MAX >> 16)))
1594 return 0;
1595
1596 *result = (hi << 16) + (XINT (low) & 0xffff);
1597 return 1;
1524 } 1598 }
1525} 1599}
1526 1600
@@ -1674,7 +1748,7 @@ For example, to produce full ISO 8601 format, use "%Y-%m-%dT%T%z". */)
1674 tm = ut ? gmtime (&value) : localtime (&value); 1748 tm = ut ? gmtime (&value) : localtime (&value);
1675 UNBLOCK_INPUT; 1749 UNBLOCK_INPUT;
1676 if (! tm) 1750 if (! tm)
1677 error ("Specified time is not representable"); 1751 time_overflow ();
1678 1752
1679 synchronize_system_time_locale (); 1753 synchronize_system_time_locale ();
1680 1754
@@ -1732,8 +1806,10 @@ DOW and ZONE.) */)
1732 BLOCK_INPUT; 1806 BLOCK_INPUT;
1733 decoded_time = localtime (&time_spec); 1807 decoded_time = localtime (&time_spec);
1734 UNBLOCK_INPUT; 1808 UNBLOCK_INPUT;
1735 if (! decoded_time) 1809 if (! (decoded_time
1736 error ("Specified time is not representable"); 1810 && MOST_NEGATIVE_FIXNUM - TM_YEAR_BASE <= decoded_time->tm_year
1811 && decoded_time->tm_year <= MOST_POSITIVE_FIXNUM - TM_YEAR_BASE))
1812 time_overflow ();
1737 XSETFASTINT (list_args[0], decoded_time->tm_sec); 1813 XSETFASTINT (list_args[0], decoded_time->tm_sec);
1738 XSETFASTINT (list_args[1], decoded_time->tm_min); 1814 XSETFASTINT (list_args[1], decoded_time->tm_min);
1739 XSETFASTINT (list_args[2], decoded_time->tm_hour); 1815 XSETFASTINT (list_args[2], decoded_time->tm_hour);
@@ -1757,6 +1833,20 @@ DOW and ZONE.) */)
1757 return Flist (9, list_args); 1833 return Flist (9, list_args);
1758} 1834}
1759 1835
1836/* Return OBJ - OFFSET, checking that OBJ is a valid fixnum and that
1837 the result is representable as an int. Assume OFFSET is small and
1838 nonnegative. */
1839static int
1840check_tm_member (Lisp_Object obj, int offset)
1841{
1842 EMACS_INT n;
1843 CHECK_NUMBER (obj);
1844 n = XINT (obj);
1845 if (! (INT_MIN + offset <= n && n - offset <= INT_MAX))
1846 time_overflow ();
1847 return n - offset;
1848}
1849
1760DEFUN ("encode-time", Fencode_time, Sencode_time, 6, MANY, 0, 1850DEFUN ("encode-time", Fencode_time, Sencode_time, 6, MANY, 0,
1761 doc: /* Convert SECOND, MINUTE, HOUR, DAY, MONTH, YEAR and ZONE to internal time. 1851 doc: /* Convert SECOND, MINUTE, HOUR, DAY, MONTH, YEAR and ZONE to internal time.
1762This is the reverse operation of `decode-time', which see. 1852This is the reverse operation of `decode-time', which see.
@@ -1785,19 +1875,12 @@ usage: (encode-time SECOND MINUTE HOUR DAY MONTH YEAR &optional ZONE) */)
1785 struct tm tm; 1875 struct tm tm;
1786 Lisp_Object zone = (nargs > 6 ? args[nargs - 1] : Qnil); 1876 Lisp_Object zone = (nargs > 6 ? args[nargs - 1] : Qnil);
1787 1877
1788 CHECK_NUMBER (args[0]); /* second */ 1878 tm.tm_sec = check_tm_member (args[0], 0);
1789 CHECK_NUMBER (args[1]); /* minute */ 1879 tm.tm_min = check_tm_member (args[1], 0);
1790 CHECK_NUMBER (args[2]); /* hour */ 1880 tm.tm_hour = check_tm_member (args[2], 0);
1791 CHECK_NUMBER (args[3]); /* day */ 1881 tm.tm_mday = check_tm_member (args[3], 0);
1792 CHECK_NUMBER (args[4]); /* month */ 1882 tm.tm_mon = check_tm_member (args[4], 1);
1793 CHECK_NUMBER (args[5]); /* year */ 1883 tm.tm_year = check_tm_member (args[5], TM_YEAR_BASE);
1794
1795 tm.tm_sec = XINT (args[0]);
1796 tm.tm_min = XINT (args[1]);
1797 tm.tm_hour = XINT (args[2]);
1798 tm.tm_mday = XINT (args[3]);
1799 tm.tm_mon = XINT (args[4]) - 1;
1800 tm.tm_year = XINT (args[5]) - TM_YEAR_BASE;
1801 tm.tm_isdst = -1; 1884 tm.tm_isdst = -1;
1802 1885
1803 if (CONSP (zone)) 1886 if (CONSP (zone))
@@ -1846,7 +1929,7 @@ usage: (encode-time SECOND MINUTE HOUR DAY MONTH YEAR &optional ZONE) */)
1846 } 1929 }
1847 1930
1848 if (time == (time_t) -1) 1931 if (time == (time_t) -1)
1849 error ("Specified time is not representable"); 1932 time_overflow ();
1850 1933
1851 return make_time (time); 1934 return make_time (time);
1852} 1935}
@@ -1881,7 +1964,7 @@ but this is considered obsolete. */)
1881 tm = localtime (&value); 1964 tm = localtime (&value);
1882 UNBLOCK_INPUT; 1965 UNBLOCK_INPUT;
1883 if (! (tm && TM_YEAR_IN_ASCTIME_RANGE (tm->tm_year) && (tem = asctime (tm)))) 1966 if (! (tm && TM_YEAR_IN_ASCTIME_RANGE (tm->tm_year) && (tem = asctime (tm))))
1884 error ("Specified time is not representable"); 1967 time_overflow ();
1885 1968
1886 /* Remove the trailing newline. */ 1969 /* Remove the trailing newline. */
1887 tem[strlen (tem) - 1] = '\0'; 1970 tem[strlen (tem) - 1] = '\0';
diff --git a/src/systime.h b/src/systime.h
index eae302904fa..cb1ea230f7d 100644
--- a/src/systime.h
+++ b/src/systime.h
@@ -144,10 +144,8 @@ extern void set_waiting_for_input (EMACS_TIME *);
144 happen when this files is used outside the src directory). 144 happen when this files is used outside the src directory).
145 Use GCPRO1 to determine if lisp.h was included. */ 145 Use GCPRO1 to determine if lisp.h was included. */
146#ifdef GCPRO1 146#ifdef GCPRO1
147/* defined in dired.c */
148extern Lisp_Object make_time (time_t);
149
150/* defined in editfns.c*/ 147/* defined in editfns.c*/
148extern Lisp_Object make_time (time_t);
151extern int lisp_time_argument (Lisp_Object, time_t *, int *); 149extern int lisp_time_argument (Lisp_Object, time_t *, int *);
152#endif 150#endif
153 151
@@ -172,4 +170,3 @@ extern int lisp_time_argument (Lisp_Object, time_t *, int *);
172#define EMACS_TIME_LE(T1, T2) (EMACS_TIME_CMP (T1, T2) <= 0) 170#define EMACS_TIME_LE(T1, T2) (EMACS_TIME_CMP (T1, T2) <= 0)
173 171
174#endif /* EMACS_SYSTIME_H */ 172#endif /* EMACS_SYSTIME_H */
175