bug-gnu-emacs
[Top][All Lists]
Advanced

[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 (&ltoday);
!   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 (&ltoday);
!   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.




reply via email to

[Prev in Thread] Current Thread [Next in Thread]