[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: Emacs current-time-string core dump on 64-bit hosts
From: |
Paul Eggert |
Subject: |
Re: Emacs current-time-string core dump on 64-bit hosts |
Date: |
Sun, 02 Apr 2006 21:44:09 -0700 |
User-agent: |
Gnus/5.1007 (Gnus v5.10.7) Emacs/21.4 (gnu/linux) |
Richard Stallman <rms@gnu.org> writes:
> Don't worry about it--just copy those 4 lines into each of the three
> .c files.
OK, here's a patch that does this. If I understand you correctly, you
want current-time-string to output a year that might contain more than
4 bytes (if it is greater than 9999, say) and might contain fewer (if
it is in the range 100-999, say). I haven't installed this patch yet,
since I wanted to double-check this with you first.
With this patch, I assume that I should also put something like this line:
#define TM_YEAR_IN_ASCTIME_RANGE(tm_year) 1
into src/s/gnu-linux.h and into src/s/gnu.h, but I'm not sure exactly
where you'd prefer it. At the end, perhaps?
2006-04-02 Paul Eggert <eggert@cs.ucla.edu>
* lib-src/b2m.c (main): Don't include <limits.h>.
(TM_YEAR_BASE): New macro.
(TM_YEAR_IN_ASCTIME_RANGE): Don't define if already defined, so
that s/ files can override this. Use the more-conservative range
1000-9999.
(main): Check for asctime returning NULL.
* lib-src/fakemail.c: Likewise.
* src/editfns.c (TM_YEAR_IN_ASCTIME_RANGE): New macro, identical to
../lib-src/b2m.c and ../lib-src/editfns.c.
(Fcurrent_time_string): Use it.
Document that the year might not consume 4 columns if it's outside
the range 1000-9999.
Check for asctime failure.
Don't assume that the output string length is always exactly 24.
Index: lib-src/b2m.c
===================================================================
RCS file: /cvsroot/emacs/emacs/lib-src/b2m.c,v
retrieving revision 1.31
diff -p -c -r1.31 b2m.c
*** lib-src/b2m.c 27 Mar 2006 20:40:05 -0000 1.31
--- lib-src/b2m.c 3 Apr 2006 04:38:37 -0000
***************
*** 26,32 ****
#undef static
#endif
- #include <limits.h>
#include <stdio.h>
#include <time.h>
#include <sys/types.h>
--- 26,31 ----
***************
*** 45,59 ****
typedef int logical;
! /* True if TM_YEAR is a struct tm's tm_year value that is acceptable
! to asctime. Glibc asctime returns a useful string unless TM_YEAR
! is nearly INT_MAX, but the C Standard lets C libraries overrun a
! buffer if TM_YEAR needs more than 4 bytes. */
! #ifdef __GLIBC__
! # define TM_YEAR_IN_ASCTIME_RANGE(tm_year) ((tm_year) <= INT_MAX - 1900)
! #else
# define TM_YEAR_IN_ASCTIME_RANGE(tm_year) \
! (-999 - 1900 <= (tm_year) && (tm_year) <= 9999 - 1900)
#endif
/*
--- 44,56 ----
typedef int logical;
! #define TM_YEAR_BASE 1900
!
! /* Nonzero if TM_YEAR is a struct tm's tm_year value that causes
! asctime to have well-defined behavior. */
! #ifndef TM_YEAR_IN_ASCTIME_RANGE
# define TM_YEAR_IN_ASCTIME_RANGE(tm_year) \
! (1000 - TM_YEAR_BASE <= (tm_year) && (tm_year) <= 9999 - TM_YEAR_BASE)
#endif
/*
*************** main (argc, argv)
*** 148,156 ****
Don't use 'ctime', as that might dump core if the hardware clock
is set to a bizarre value. */
tm = localtime (<oday);
! if (! (tm && TM_YEAR_IN_ASCTIME_RANGE (tm->tm_year)))
fatal ("current time is out of range");
- today = asctime (tm);
data.size = 200;
data.buffer = xnew (200, char);
--- 145,153 ----
Don't use 'ctime', as that might dump core if the hardware clock
is set to a bizarre value. */
tm = localtime (<oday);
! if (! (tm && TM_YEAR_IN_ASCTIME_RANGE (tm->tm_year)
! && (today = asctime (tm))))
fatal ("current time is out of range");
data.size = 200;
data.buffer = xnew (200, char);
Index: lib-src/fakemail.c
===================================================================
RCS file: /cvsroot/emacs/emacs/lib-src/fakemail.c,v
retrieving revision 1.36
diff -p -c -r1.36 fakemail.c
*** lib-src/fakemail.c 27 Mar 2006 20:40:05 -0000 1.36
--- lib-src/fakemail.c 3 Apr 2006 04:38:37 -0000
*************** main ()
*** 53,59 ****
#include "ntlib.h"
#endif
- #include <limits.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
--- 53,58 ----
*************** main ()
*** 71,85 ****
#define true 1
#define false 0
! /* True if TM_YEAR is a struct tm's tm_year value that is acceptable
! to asctime. Glibc asctime returns a useful string unless TM_YEAR
! is nearly INT_MAX, but the C Standard lets C libraries overrun a
! buffer if TM_YEAR needs more than 4 bytes. */
! #ifdef __GLIBC__
! # define TM_YEAR_IN_ASCTIME_RANGE(tm_year) ((tm_year) <= INT_MAX - 1900)
! #else
# define TM_YEAR_IN_ASCTIME_RANGE(tm_year) \
! (-999 - 1900 <= (tm_year) && (tm_year) <= 9999 - 1900)
#endif
/* Various lists */
--- 70,82 ----
#define true 1
#define false 0
! #define TM_YEAR_BASE 1900
!
! /* Nonzero if TM_YEAR is a struct tm's tm_year value that causes
! asctime to have well-defined behavior. */
! #ifndef TM_YEAR_IN_ASCTIME_RANGE
# define TM_YEAR_IN_ASCTIME_RANGE(tm_year) \
! (1000 - TM_YEAR_BASE <= (tm_year) && (tm_year) <= 9999 - TM_YEAR_BASE)
#endif
/* Various lists */
*************** make_file_preface ()
*** 378,386 ****
Don't use 'ctime', as that might dump core if the hardware clock
is set to a bizarre value. */
tm = localtime (&idiotic_interface);
! if (! (tm && TM_YEAR_IN_ASCTIME_RANGE (tm->tm_year)))
fatal ("current time is out of range", 0);
- the_date = asctime (tm);
/* the_date has an unwanted newline at the end */
date_length = strlen (the_date) - 1;
the_date[date_length] = '\0';
--- 375,383 ----
Don't use 'ctime', as that might dump core if the hardware clock
is set to a bizarre value. */
tm = localtime (&idiotic_interface);
! if (! (tm && TM_YEAR_IN_ASCTIME_RANGE (tm->tm_year)
! && (the_date = asctime (tm))))
fatal ("current time is out of range", 0);
/* the_date has an unwanted newline at the end */
date_length = strlen (the_date) - 1;
the_date[date_length] = '\0';
Index: src/editfns.c
===================================================================
RCS file: /cvsroot/emacs/emacs/src/editfns.c,v
retrieving revision 1.411
diff -p -c -r1.411 editfns.c
*** src/editfns.c 25 Mar 2006 08:56:07 -0000 1.411
--- src/editfns.c 3 Apr 2006 04:38:37 -0000
*************** extern char **environ;
*** 74,79 ****
--- 74,86 ----
#define TM_YEAR_BASE 1900
+ /* Nonzero if TM_YEAR is a struct tm's tm_year value that causes
+ asctime to have well-defined behavior. */
+ #ifndef TM_YEAR_IN_ASCTIME_RANGE
+ # define TM_YEAR_IN_ASCTIME_RANGE(tm_year) \
+ (1000 - TM_YEAR_BASE <= (tm_year) && (tm_year) <= 9999 - TM_YEAR_BASE)
+ #endif
+
extern size_t emacs_strftimeu P_ ((char *, size_t, const char *,
const struct tm *, int));
static int tm_diff P_ ((struct tm *, struct tm *));
*************** usage: (encode-time SECOND MINUTE HOUR D
*** 1833,1839 ****
DEFUN ("current-time-string", Fcurrent_time_string, Scurrent_time_string, 0,
1, 0,
doc: /* Return the current time, as a human-readable string.
Programs can use this function to decode a time,
! since the number of columns in each field is fixed.
The format is `Sun Sep 16 01:03:52 1973'.
However, see also the functions `decode-time' and `format-time-string'
which provide a much more powerful and general facility.
--- 1840,1847 ----
DEFUN ("current-time-string", Fcurrent_time_string, Scurrent_time_string, 0,
1, 0,
doc: /* Return the current time, as a human-readable string.
Programs can use this function to decode a time,
! since the number of columns in each field is fixed
! if the year is in the range 1000-9999.
The format is `Sun Sep 16 01:03:52 1973'.
However, see also the functions `decode-time' and `format-time-string'
which provide a much more powerful and general facility.
*************** but this is considered obsolete. */)
*** 1847,1877 ****
Lisp_Object specified_time;
{
time_t value;
- char buf[30];
struct tm *tm;
register char *tem;
if (! lisp_time_argument (specified_time, &value, NULL))
error ("Invalid time specification");
! /* Do not use ctime, since it has undefined behavior with
! out-of-range time stamps. This avoids a core dump triggered by
! (current-time-string '(2814749767106 0)) on 64-bit Solaris 8. See
! <http://www.opengroup.org/austin/mailarchives/ag/msg09294.html>
! for more details about this portability problem. */
tm = localtime (&value);
! /* Checking for out-of-range time stamps avoids buffer overruns that
! cause core dump on some systems (e.g., 64-bit Solaris), and also
! preserves the historic behavior of always returning a fixed-size
! 24-character string. */
! if (! (tm && -999 - TM_YEAR_BASE <= tm->tm_year
! && tm->tm_year <= 9999 - TM_YEAR_BASE))
error ("Specified time is not representable");
- tem = asctime (tm);
! strncpy (buf, tem, 24);
! buf[24] = 0;
! return build_string (buf);
}
/* Yield A - B, measured in seconds.
--- 1855,1877 ----
Lisp_Object specified_time;
{
time_t value;
struct tm *tm;
register char *tem;
if (! lisp_time_argument (specified_time, &value, NULL))
error ("Invalid time specification");
!
! /* Convert to a string, checking for out-of-range time stamps.
! Don't use 'ctime', as that might dump core if VALUE is out of
! range. */
tm = localtime (&value);
! if (! (tm && TM_YEAR_IN_ASCTIME_RANGE (tm->tm_year) && (tem = asctime
(tm))))
error ("Specified time is not representable");
! /* Remove the trailing newline. */
! tem[strlen (tem) - 1] = '\0';
! return build_string (tem);
}
/* Yield A - B, measured in seconds.