From: Paul Eggert <eggert@CS.UCLA.EDU>
Subject: Emacs current-time-string core dump on 64-bit hosts
Date: Fri, 17 Mar 2006 00:02:13 -0800 [thread overview]
Message-ID: <87hd5xeby2.fsf@penguin.cs.ucla.edu> (raw)
GNU Emacs 21.4.1 (sparc-sun-solaris2.8, X toolkit), built with
"CC='gcc -m64' ./configure" to get 64-bit mode, reliably dumps core
when I execute (current-time-string '(2814749767106 0)), due to a
buffer overrun inside the C library. This is because Emacs is relying
on undefined behavior within the ctime() call.
I discovered this problem after reporting a bug in the POSIX
specification for ctime; see
<http://www.opengroup.org/austin/mailarchives/ag/msg09294.html>.
In practice, ctime (as well as ctime_r, asctime, and asctime_r)
cannot be trusted with arbitrary time stamps, any more than gets
can be trusted with arbitrary inputs: if the time stamps generate
a string that is too long, the program can do anything.
Here is a proposed patch, relative to CVS head.
2006-03-16 Paul Eggert <eggert@cs.ucla.edu>
Do not use ctime, since it has undefined behavior with
out-of-range time stamps. This fixes a bug where
(current-time-string '(2814749767106 0)) would make Emacs dump
core on 64-bit Solaris 8; the fix is to remove all uses of ctime
from the Emacs source code. Please see
<http://www.opengroup.org/austin/mailarchives/ag/msg09294.html>
for more details about this portability problem.
* lib-src/b2m.c: Include <limits.h>, for CHAR_BIT.
(TM_YEAR_BASE): New macro.
(string_from_time): New function.
(main): Use it instead of ctime, to avoid buffer overflows with
outlandish time stamps.
* lib-src/fakemail.c: Likewise.
* src/editfns.c: Include <limits.h>, for CHAR_BIT.
(TM_YEAR_BASE): Move up, so new code can use it.
(Fdecode_time, Fencode_time):
Use TM_YEAR_BASE instead of hardwiring 1900.
(Fdecode_time): Cast tm_year to EMACS_INT, to avoid overflow when
int is narrow than EMACS_INT.
(Fcurrent_time_string): Do not use ctime, since it might
cause a buffer overflow with outlandish time stamps.
Instead, implement its algorithm ourselves.
As with Fformat_time_string, report an invalid time specification
if the argument is invalid, and report an out-of-range time stamp
if that problem occurs. This is better than overrunning the buffer,
and it preserves the historic behavior of always returning a
fixed-size string.
* lib-src/ntlib.c (sys_ctime): Remove, since Emacs never calls
ctime any more.
* lib-src/ntlib.h (ctime): Likewise.
* src/w32.c (sys_ctime): Likewise.
* src/s/ms-w32.h (ctime): Likewise.
Index: lib-src/b2m.c
===================================================================
RCS file: /cvsroot/emacs/emacs/lib-src/b2m.c,v
retrieving revision 1.30
diff -p -u -r1.30 b2m.c
--- lib-src/b2m.c 7 May 2004 15:26:21 -0000 1.30
+++ lib-src/b2m.c 17 Mar 2006 05:22:00 -0000
@@ -26,6 +26,7 @@
#undef static
#endif
+#include <limits.h>
#include <stdio.h>
#include <time.h>
#include <sys/types.h>
@@ -68,6 +69,35 @@ void fatal ();
#define xnew(n, Type) ((Type *) xmalloc ((n) * sizeof (Type)))
+#define TM_YEAR_BASE 1900
+
+static char *
+string_from_time (time_t t)
+{
+ static char buf[sizeof "Sun Sep 16 01:03:52 "
+ + sizeof (long int) * CHAR_BIT / 3];
+ struct tm const *tm = localtime (&t);
+ if (! tm)
+ sprintf (buf, "@%ld", (long int) t);
+ else
+ {
+ static char const wday[][4] =
+ {
+ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
+ };
+ static char const mon[][4] =
+ {
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+ };
+ sprintf (buf, "%s %s %2d %.2d:%.2d:%.2d %ld",
+ wday[tm->tm_wday], mon[tm->tm_mon], tm->tm_mday,
+ tm->tm_hour, tm->tm_min, tm->tm_sec,
+ TM_YEAR_BASE + (long int) tm->tm_year);
+ }
+ return buf;
+}
+
char *progname;
@@ -131,7 +161,7 @@ main (argc, argv)
labels_saved = printing = header = FALSE;
ltoday = time (0);
- today = ctime (<oday);
+ today = string_from_time (ltoday);
data.size = 200;
data.buffer = xnew (200, char);
@@ -144,7 +174,7 @@ main (argc, argv)
if (streq (data.buffer, "*** EOOH ***") && !printing)
{
printing = header = TRUE;
- printf ("From \"Babyl to mail by %s\" %s", progname, today);
+ printf ("From \"Babyl to mail by %s\" %s\n", progname, today);
continue;
}
Index: lib-src/fakemail.c
===================================================================
RCS file: /cvsroot/emacs/emacs/lib-src/fakemail.c,v
retrieving revision 1.35
diff -p -u -r1.35 fakemail.c
--- lib-src/fakemail.c 6 Feb 2006 11:28:28 -0000 1.35
+++ lib-src/fakemail.c 17 Mar 2006 05:22:01 -0000
@@ -53,6 +53,7 @@ main ()
#include "ntlib.h"
#endif
+#include <limits.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
@@ -349,22 +350,47 @@ add_field (the_list, field, where)
return where;
}
\f
+#define TM_YEAR_BASE 1900
+
+static char *
+string_from_time (time_t t)
+{
+ static char buf[sizeof "Sun Sep 16 01:03:52 "
+ + sizeof (long int) * CHAR_BIT / 3];
+ struct tm const *tm = localtime (&t);
+ if (! tm)
+ sprintf (buf, "@%ld", (long int) t);
+ else
+ {
+ static char const wday[][4] =
+ {
+ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
+ };
+ static char const mon[][4] =
+ {
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+ };
+ sprintf (buf, "%s %s %2d %.2d:%.2d:%.2d %ld",
+ wday[tm->tm_wday], mon[tm->tm_mon], tm->tm_mday,
+ tm->tm_hour, tm->tm_min, tm->tm_sec,
+ TM_YEAR_BASE + (long int) tm->tm_year);
+ }
+ return buf;
+}
+
line_list
make_file_preface ()
{
char *the_string, *temp;
- long idiotic_interface;
long prefix_length;
long user_length;
long date_length;
line_list result;
prefix_length = strlen (FROM_PREFIX);
- time (&idiotic_interface);
- the_date = ctime (&idiotic_interface);
- /* the_date has an unwanted newline at the end */
- date_length = strlen (the_date) - 1;
- the_date[date_length] = '\0';
+ the_date = string_from_time (time (NULL));
+ date_length = strlen (the_date);
temp = cuserid ((char *) NULL);
user_length = strlen (temp);
the_user = alloc_string (user_length + 1);
Index: src/editfns.c
===================================================================
RCS file: /cvsroot/emacs/emacs/src/editfns.c,v
retrieving revision 1.409
diff -p -u -r1.409 editfns.c
--- src/editfns.c 7 Feb 2006 09:08:53 -0000 1.409
+++ src/editfns.c 17 Mar 2006 05:22:01 -0000
@@ -49,6 +49,7 @@ Boston, MA 02110-1301, USA. */
#endif
#include <ctype.h>
+#include <limits.h>
#include "intervals.h"
#include "buffer.h"
@@ -72,6 +73,8 @@ Boston, MA 02110-1301, USA. */
extern char **environ;
#endif
+#define TM_YEAR_BASE 1900
+
extern size_t emacs_strftimeu P_ ((char *, size_t, const char *,
const struct tm *, int));
static int tm_diff P_ ((struct tm *, struct tm *));
@@ -1722,7 +1725,7 @@ DOW and ZONE.) */)
XSETFASTINT (list_args[2], decoded_time->tm_hour);
XSETFASTINT (list_args[3], decoded_time->tm_mday);
XSETFASTINT (list_args[4], decoded_time->tm_mon + 1);
- XSETINT (list_args[5], decoded_time->tm_year + 1900);
+ XSETINT (list_args[5], TM_YEAR_BASE + (EMACS_INT) decoded_time->tm_year);
XSETFASTINT (list_args[6], decoded_time->tm_wday);
list_args[7] = (decoded_time->tm_isdst)? Qt : Qnil;
@@ -1778,7 +1781,7 @@ usage: (encode-time SECOND MINUTE HOUR D
tm.tm_hour = XINT (args[2]);
tm.tm_mday = XINT (args[3]);
tm.tm_mon = XINT (args[4]) - 1;
- tm.tm_year = XINT (args[5]) - 1900;
+ tm.tm_year = XINT (args[5]) - TM_YEAR_BASE;
tm.tm_isdst = -1;
if (CONSP (zone))
@@ -1843,21 +1846,34 @@ but this is considered obsolete. */)
Lisp_Object specified_time;
{
time_t value;
- char buf[30];
- register char *tem;
+ char buf[sizeof "Sun Sep 16 01:03:52 1973"];
+ struct tm const *tm;
+ static char const wday[][4] =
+ {
+ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
+ };
+ static char const mon[][4] =
+ {
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+ };
if (! lisp_time_argument (specified_time, &value, NULL))
- value = -1;
- tem = (char *) ctime (&value);
+ error ("Invalid time specification");
- strncpy (buf, tem, 24);
- buf[24] = 0;
+ tm = localtime (&value);
+ if (! (tm
+ && -999 - TM_YEAR_BASE <= tm->tm_year
+ && tm->tm_year <= 9999 - TM_YEAR_BASE))
+ error ("Specified time is not representable");
+ sprintf (buf, "%s %s %2d %02d:%02d:%02d %04d",
+ wday[tm->tm_wday], mon[tm->tm_mon], tm->tm_mday,
+ tm->tm_hour, tm->tm_min, tm->tm_sec,
+ TM_YEAR_BASE + tm->tm_year);
return build_string (buf);
}
-#define TM_YEAR_BASE 1900
-
/* Yield A - B, measured in seconds.
This function is copied from the GNU C Library. */
static int
Index: lib-src/ntlib.c
===================================================================
RCS file: /cvsroot/emacs/emacs/lib-src/ntlib.c,v
retrieving revision 1.13
diff -p -u -r1.13 ntlib.c
--- lib-src/ntlib.c 6 Feb 2006 11:28:28 -0000 1.13
+++ lib-src/ntlib.c 17 Mar 2006 05:22:01 -0000
@@ -188,16 +188,6 @@ fchown (int fd, int uid, int gid)
return 0;
}
-/* Place a wrapper around the MSVC version of ctime. It returns NULL
- on network directories, so we handle that case here.
- (Ulrich Leodolter, 1/11/95). */
-char *
-sys_ctime (const time_t *t)
-{
- char *str = (char *) ctime (t);
- return (str ? str : "Sun Jan 01 00:00:00 1970");
-}
-
FILE *
sys_fopen(const char * path, const char * mode)
{
Index: lib-src/ntlib.h
===================================================================
RCS file: /cvsroot/emacs/emacs/lib-src/ntlib.h,v
retrieving revision 1.11
diff -p -u -r1.11 ntlib.h
--- lib-src/ntlib.h 6 Feb 2006 11:28:28 -0000 1.11
+++ lib-src/ntlib.h 17 Mar 2006 05:22:01 -0000
@@ -61,7 +61,6 @@ int fchown (int fd, int uid, int gid);
#define close _close
#undef creat
#define creat _creat
-#undef ctime
#undef dup
#define dup _dup
#undef dup2
Index: src/w32.c
===================================================================
RCS file: /cvsroot/emacs/emacs/src/w32.c,v
retrieving revision 1.100
diff -p -u -r1.100 w32.c
--- src/w32.c 27 Feb 2006 02:07:37 -0000 1.100
+++ src/w32.c 17 Mar 2006 05:22:01 -0000
@@ -1325,16 +1325,6 @@ gettimeofday (struct timeval *tv, struct
/* IO support and wrapper functions for W32 API. */
/* ------------------------------------------------------------------------- */
-/* Place a wrapper around the MSVC version of ctime. It returns NULL
- on network directories, so we handle that case here.
- (Ulrich Leodolter, 1/11/95). */
-char *
-sys_ctime (const time_t *t)
-{
- char *str = (char *) ctime (t);
- return (str ? str : "Sun Jan 01 00:00:00 1970");
-}
-
/* Emulate sleep...we could have done this with a define, but that
would necessitate including windows.h in the files that used it.
This is much easier. */
Index: src/s/ms-w32.h
===================================================================
RCS file: /cvsroot/emacs/emacs/src/s/ms-w32.h,v
retrieving revision 1.37
diff -p -u -r1.37 ms-w32.h
--- src/s/ms-w32.h 6 Feb 2006 15:23:23 -0000 1.37
+++ src/s/ms-w32.h 17 Mar 2006 05:22:01 -0000
@@ -317,7 +317,6 @@ Boston, MA 02110-1301, USA. */
#define close sys_close
#undef creat
#define creat sys_creat
-#define ctime sys_ctime
#undef dup
#define dup sys_dup
#undef dup2
next reply other threads:[~2006-03-17 8:02 UTC|newest]
Thread overview: 41+ messages / expand[flat|nested] mbox.gz Atom feed top
2006-03-17 8:02 Paul Eggert [this message]
-- strict thread matches above, loose matches on Subject: below --
2006-03-17 5:58 Emacs current-time-string core dump on 64-bit hosts Paul Eggert
2006-03-17 12:16 ` Eli Zaretskii
2006-03-17 12:46 ` Andreas Schwab
2006-03-17 16:04 ` Kevin Rodgers
2006-03-18 0:44 ` Paul Eggert
2006-03-18 11:50 ` Eli Zaretskii
2006-03-19 2:30 ` Paul Eggert
2006-03-21 19:25 ` Richard Stallman
2006-03-18 8:43 ` Richard Stallman
2006-03-19 1:53 ` Paul Eggert
2006-03-19 21:50 ` Richard Stallman
2006-03-19 23:44 ` Paul Eggert
2006-03-20 19:59 ` Eli Zaretskii
2006-03-27 22:00 ` Paul Eggert
2006-03-28 10:16 ` Eli Zaretskii
2006-03-30 7:52 ` Paul Eggert
2006-03-30 20:36 ` Eli Zaretskii
2006-04-04 4:57 ` Paul Eggert
2006-04-04 18:20 ` Eli Zaretskii
2006-03-21 1:00 ` Richard Stallman
2006-03-24 20:45 ` Paul Eggert
2006-03-25 9:10 ` Eli Zaretskii
2006-03-26 5:25 ` Paul Eggert
2006-03-26 20:06 ` Eli Zaretskii
2006-03-27 22:29 ` Richard Stallman
2006-03-28 10:20 ` Eli Zaretskii
2006-03-29 8:14 ` Richard Stallman
2006-03-25 15:26 ` Richard Stallman
2006-03-24 21:00 ` Paul Eggert
2006-03-24 21:09 ` Paul Eggert
2006-03-25 15:26 ` Richard Stallman
2006-03-26 7:31 ` Paul Eggert
[not found] ` <E1FNnCd-0000pN-J4@fencepost.gnu.org>
2006-03-27 20:49 ` Paul Eggert
2006-03-28 19:33 ` Richard Stallman
2006-03-30 7:57 ` Paul Eggert
2006-03-31 17:28 ` Richard Stallman
2006-03-31 20:51 ` Paul Eggert
2006-04-01 20:28 ` Richard Stallman
2006-04-03 4:44 ` Paul Eggert
2006-03-17 16:25 ` Andreas Schwab
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
List information: https://www.gnu.org/software/emacs/
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=87hd5xeby2.fsf@penguin.cs.ucla.edu \
--to=eggert@cs.ucla.edu \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this public inbox
https://git.savannah.gnu.org/cgit/emacs.git
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).