summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib-src/ChangeLog35
-rw-r--r--lib-src/emacsclient.c95
-rw-r--r--lib-src/etags.c44
-rw-r--r--lib-src/movemail.c7
-rw-r--r--lib-src/update-game-score.c15
-rw-r--r--src/ChangeLog105
-rw-r--r--src/dbusbind.c41
-rw-r--r--src/dispnew.c19
-rw-r--r--src/doprnt.c224
-rw-r--r--src/editfns.c5
-rw-r--r--src/emacs.c8
-rw-r--r--src/eval.c26
-rw-r--r--src/filelock.c35
-rw-r--r--src/font.c174
-rw-r--r--src/fontset.c6
-rw-r--r--src/frame.c46
-rw-r--r--src/gtkutil.c5
-rw-r--r--src/keyboard.c46
-rw-r--r--src/keymap.c19
-rw-r--r--src/lisp.h14
-rw-r--r--src/lread.c16
-rw-r--r--src/macros.c12
-rw-r--r--src/macros.h3
-rw-r--r--src/minibuf.c8
-rw-r--r--src/nsterm.m2
-rw-r--r--src/print.c35
-rw-r--r--src/process.c6
-rw-r--r--src/term.c2
-rw-r--r--src/window.h4
-rw-r--r--src/xfaces.c35
-rw-r--r--src/xfns.c2
-rw-r--r--src/xterm.c3
-rw-r--r--src/xterm.h3
33 files changed, 702 insertions, 398 deletions
diff --git a/lib-src/ChangeLog b/lib-src/ChangeLog
index c878d313b70..e8a0b13f419 100644
--- a/lib-src/ChangeLog
+++ b/lib-src/ChangeLog
@@ -1,3 +1,38 @@
+2011-08-28 Paul Eggert <eggert@cs.ucla.edu>
+
+ Integer and memory overflow issues (Bug#9397).
+
+ * emacsclient.c (xmalloc): Accept size_t, not unsigned int, to
+ avoid potential buffer overflow issues on typical 64-bit hosts.
+ Return void *, not long *.
+ (get_current_dir_name): Report a failure, instead of looping
+ forever, if buffer size calculation overflows. Treat malloc
+ failures like realloc failures, as that has better behavior and is
+ more consistent. Do not check whether xmalloc returns NULL, as
+ that's not possible.
+ (message): Do not arbitrarily truncate message to 2048 bytes when
+ sending it to stderr; use vfprintf instead.
+ (get_server_config, set_local_socket)
+ (start_daemon_and_retry_set_socket): Do not alloca
+ arbitrarily-large buffers; that's not safe.
+ (get_server_config, set_local_socket): Do not use sprintf when its
+ result might not fit in 'int'.
+ (set_local_socket): Do not assume uid fits in 'int'.
+
+ * etags.c (xmalloc, xrealloc): Accept size_t, not unsigned int,
+ to avoid potential buffer overflow issues on typical 64-bit hosts.
+ (whatlen_max): New static var.
+ (main): Avoid buffer overflow if subsidiary command length is
+ greater than BUFSIZ or 2*BUFSIZ + 20. Do not use sprintf when its
+ result might not fit in 'int'.
+
+ * movemail.c (main): Do not use sprintf when its result might not fit
+ in 'int'. Instead, put the possibly-long file name into the
+ output of pfatal_with_name.
+
+ * update-game-score.c: Include <limits.h>
+ (get_user_id): Do not assume uid fits in 'int'. Simplify.
+
2011-07-28 Paul Eggert <eggert@cs.ucla.edu>
Assume freestanding C89 headers, string.h, stdlib.h.
diff --git a/lib-src/emacsclient.c b/lib-src/emacsclient.c
index 2af139aee6d..ece9dc65c49 100644
--- a/lib-src/emacsclient.c
+++ b/lib-src/emacsclient.c
@@ -194,10 +194,10 @@ struct option longopts[] =
/* Like malloc but get fatal error if memory is exhausted. */
-static long *
-xmalloc (unsigned int size)
+static void *
+xmalloc (size_t size)
{
- long *result = (long *) malloc (size);
+ void *result = malloc (size);
if (result == NULL)
{
perror ("malloc");
@@ -250,32 +250,33 @@ get_current_dir_name (void)
)
{
buf = (char *) xmalloc (strlen (pwd) + 1);
- if (!buf)
- return NULL;
strcpy (buf, pwd);
}
#ifdef HAVE_GETCWD
else
{
size_t buf_size = 1024;
- buf = (char *) xmalloc (buf_size);
- if (!buf)
- return NULL;
for (;;)
{
+ int tmp_errno;
+ buf = malloc (buf_size);
+ if (! buf)
+ break;
if (getcwd (buf, buf_size) == buf)
break;
- if (errno != ERANGE)
+ tmp_errno = errno;
+ free (buf);
+ if (tmp_errno != ERANGE)
{
- int tmp_errno = errno;
- free (buf);
errno = tmp_errno;
return NULL;
}
buf_size *= 2;
- buf = (char *) realloc (buf, buf_size);
- if (!buf)
- return NULL;
+ if (! buf_size)
+ {
+ errno = ENOMEM;
+ return NULL;
+ }
}
}
#else
@@ -283,8 +284,6 @@ get_current_dir_name (void)
{
/* We need MAXPATHLEN here. */
buf = (char *) xmalloc (MAXPATHLEN + 1);
- if (!buf)
- return NULL;
if (getwd (buf) == NULL)
{
int tmp_errno = errno;
@@ -494,16 +493,17 @@ static void message (int, const char *, ...) ATTRIBUTE_FORMAT_PRINTF (2, 3);
static void
message (int is_error, const char *format, ...)
{
- char msg[2048];
va_list args;
va_start (args, format);
- vsprintf (msg, format, args);
- va_end (args);
#ifdef WINDOWSNT
if (w32_window_app ())
{
+ char msg[2048];
+ vsnprintf (msg, sizeof msg, format, args);
+ msg[sizeof msg - 1] = '\0';
+
if (is_error)
MessageBox (NULL, msg, "Emacsclient ERROR", MB_ICONERROR);
else
@@ -514,9 +514,11 @@ message (int is_error, const char *format, ...)
{
FILE *f = is_error ? stderr : stdout;
- fputs (msg, f);
+ vfprintf (f, format, args);
fflush (f);
}
+
+ va_end (args);
}
/* Decode the options from argv and argc.
@@ -959,18 +961,24 @@ get_server_config (struct sockaddr_in *server, char *authentication)
if (home)
{
- char *path = alloca (strlen (home) + strlen (server_file)
- + EXTRA_SPACE);
- sprintf (path, "%s/.emacs.d/server/%s", home, server_file);
+ char *path = xmalloc (strlen (home) + strlen (server_file)
+ + EXTRA_SPACE);
+ strcpy (path, home);
+ strcat (path, "/.emacs.d/server/");
+ strcat (path, server_file);
config = fopen (path, "rb");
+ free (path);
}
#ifdef WINDOWSNT
if (!config && (home = egetenv ("APPDATA")))
{
- char *path = alloca (strlen (home) + strlen (server_file)
- + EXTRA_SPACE);
- sprintf (path, "%s/.emacs.d/server/%s", home, server_file);
+ char *path = xmalloc (strlen (home) + strlen (server_file)
+ + EXTRA_SPACE);
+ strcpy (path, home);
+ strcat (path, "/.emacs.d/server/");
+ strcat (path, server_file);
config = fopen (path, "rb");
+ free (path);
}
#endif
}
@@ -1243,6 +1251,8 @@ set_local_socket (void)
int saved_errno = 0;
const char *server_name = "server";
const char *tmpdir IF_LINT ( = NULL);
+ char *tmpdir_storage = NULL;
+ char *socket_name_storage = NULL;
if (socket_name && !strchr (socket_name, '/')
&& !strchr (socket_name, '\\'))
@@ -1255,6 +1265,8 @@ set_local_socket (void)
if (default_sock)
{
+ long uid = geteuid ();
+ ptrdiff_t tmpdirlen;
tmpdir = egetenv ("TMPDIR");
if (!tmpdir)
{
@@ -1265,17 +1277,19 @@ set_local_socket (void)
size_t n = confstr (_CS_DARWIN_USER_TEMP_DIR, NULL, (size_t) 0);
if (n > 0)
{
- tmpdir = alloca (n);
+ tmpdir = tmpdir_storage = xmalloc (n);
confstr (_CS_DARWIN_USER_TEMP_DIR, tmpdir, n);
}
else
#endif
tmpdir = "/tmp";
}
- socket_name = alloca (strlen (tmpdir) + strlen (server_name)
- + EXTRA_SPACE);
- sprintf (socket_name, "%s/emacs%d/%s",
- tmpdir, (int) geteuid (), server_name);
+ tmpdirlen = strlen (tmpdir);
+ socket_name = socket_name_storage =
+ xmalloc (tmpdirlen + strlen (server_name) + EXTRA_SPACE);
+ strcpy (socket_name, tmpdir);
+ sprintf (socket_name + tmpdirlen, "/emacs%ld/", uid);
+ strcat (socket_name + tmpdirlen, server_name);
}
if (strlen (socket_name) < sizeof (server.sun_path))
@@ -1309,10 +1323,13 @@ set_local_socket (void)
if (pw && (pw->pw_uid != geteuid ()))
{
/* We're running under su, apparently. */
- socket_name = alloca (strlen (tmpdir) + strlen (server_name)
- + EXTRA_SPACE);
- sprintf (socket_name, "%s/emacs%d/%s",
- tmpdir, (int) pw->pw_uid, server_name);
+ long uid = pw->pw_uid;
+ ptrdiff_t tmpdirlen = strlen (tmpdir);
+ socket_name = xmalloc (tmpdirlen + strlen (server_name)
+ + EXTRA_SPACE);
+ strcpy (socket_name, tmpdir);
+ sprintf (socket_name + tmpdirlen, "/emacs%ld/", uid);
+ strcat (socket_name + tmpdirlen, server_name);
if (strlen (socket_name) < sizeof (server.sun_path))
strcpy (server.sun_path, socket_name);
@@ -1322,6 +1339,7 @@ set_local_socket (void)
progname, socket_name);
exit (EXIT_FAILURE);
}
+ free (socket_name);
sock_status = socket_status (server.sun_path);
saved_errno = errno;
@@ -1331,6 +1349,9 @@ set_local_socket (void)
}
}
+ free (socket_name_storage);
+ free (tmpdir_storage);
+
switch (sock_status)
{
case 1:
@@ -1526,8 +1547,8 @@ start_daemon_and_retry_set_socket (void)
{
/* Pass --daemon=socket_name as argument. */
const char *deq = "--daemon=";
- char *daemon_arg = alloca (strlen (deq)
- + strlen (socket_name) + 1);
+ char *daemon_arg = xmalloc (strlen (deq)
+ + strlen (socket_name) + 1);
strcpy (daemon_arg, deq);
strcat (daemon_arg, socket_name);
d_argv[1] = daemon_arg;
diff --git a/lib-src/etags.c b/lib-src/etags.c
index 522c54ee4a5..9d920565804 100644
--- a/lib-src/etags.c
+++ b/lib-src/etags.c
@@ -414,8 +414,8 @@ static bool filename_is_absolute (char *f);
static void canonicalize_filename (char *);
static void linebuffer_init (linebuffer *);
static void linebuffer_setlen (linebuffer *, int);
-static PTR xmalloc (unsigned int);
-static PTR xrealloc (char *, unsigned int);
+static PTR xmalloc (size_t);
+static PTR xrealloc (char *, size_t);
static char searchar = '/'; /* use /.../ searches */
@@ -425,6 +425,7 @@ static char *progname; /* name this program was invoked with */
static char *cwd; /* current working directory */
static char *tagfiledir; /* directory of tagfile */
static FILE *tagf; /* ioptr for tags file */
+static ptrdiff_t whatlen_max; /* maximum length of any 'what' member */
static fdesc *fdhead; /* head of file description list */
static fdesc *curfdp; /* current file description */
@@ -1066,6 +1067,7 @@ main (int argc, char **argv)
int current_arg, file_count;
linebuffer filename_lb;
bool help_asked = FALSE;
+ ptrdiff_t len;
char *optstring;
int opt;
@@ -1110,6 +1112,9 @@ main (int argc, char **argv)
/* This means that a file name has been seen. Record it. */
argbuffer[current_arg].arg_type = at_filename;
argbuffer[current_arg].what = optarg;
+ len = strlen (optarg);
+ if (whatlen_max < len)
+ whatlen_max = len;
++current_arg;
++file_count;
break;
@@ -1118,6 +1123,9 @@ main (int argc, char **argv)
/* Parse standard input. Idea by Vivek <vivek@etla.org>. */
argbuffer[current_arg].arg_type = at_stdin;
argbuffer[current_arg].what = optarg;
+ len = strlen (optarg);
+ if (whatlen_max < len)
+ whatlen_max = len;
++current_arg;
++file_count;
if (parsing_stdin)
@@ -1160,6 +1168,9 @@ main (int argc, char **argv)
case 'r':
argbuffer[current_arg].arg_type = at_regexp;
argbuffer[current_arg].what = optarg;
+ len = strlen (optarg);
+ if (whatlen_max < len)
+ whatlen_max = len;
++current_arg;
break;
case 'R':
@@ -1198,6 +1209,9 @@ main (int argc, char **argv)
{
argbuffer[current_arg].arg_type = at_filename;
argbuffer[current_arg].what = argv[optind];
+ len = strlen (argv[optind]);
+ if (whatlen_max < len)
+ whatlen_max = len;
++current_arg;
++file_count;
}
@@ -1331,7 +1345,9 @@ main (int argc, char **argv)
/* From here on, we are in (CTAGS && !cxref_style) */
if (update)
{
- char cmd[BUFSIZ];
+ char *cmd =
+ xmalloc (strlen (tagfile) + whatlen_max +
+ sizeof "mv..OTAGS;fgrep -v '\t\t' OTAGS >;rm OTAGS");
for (i = 0; i < current_arg; ++i)
{
switch (argbuffer[i].arg_type)
@@ -1342,12 +1358,17 @@ main (int argc, char **argv)
default:
continue; /* the for loop */
}
- sprintf (cmd,
- "mv %s OTAGS;fgrep -v '\t%s\t' OTAGS >%s;rm OTAGS",
- tagfile, argbuffer[i].what, tagfile);
+ strcpy (cmd, "mv ");
+ strcat (cmd, tagfile);
+ strcat (cmd, " OTAGS;fgrep -v '\t");
+ strcat (cmd, argbuffer[i].what);
+ strcat (cmd, "\t' OTAGS >");
+ strcat (cmd, tagfile);
+ strcat (cmd, ";rm OTAGS");
if (system (cmd) != EXIT_SUCCESS)
fatal ("failed to execute shell command", (char *)NULL);
}
+ free (cmd);
append_to_tagfile = TRUE;
}
@@ -1363,11 +1384,14 @@ main (int argc, char **argv)
if (CTAGS)
if (append_to_tagfile || update)
{
- char cmd[2*BUFSIZ+20];
+ char *cmd = xmalloc (2 * strlen (tagfile) + sizeof "sort -u -o..");
/* Maybe these should be used:
setenv ("LC_COLLATE", "C", 1);
setenv ("LC_ALL", "C", 1); */
- sprintf (cmd, "sort -u -o %.*s %.*s", BUFSIZ, tagfile, BUFSIZ, tagfile);
+ strcpy (cmd, "sort -u -o ");
+ strcat (cmd, tagfile);
+ strcat (cmd, " ");
+ strcat (cmd, tagfile);
exit (system (cmd));
}
return EXIT_SUCCESS;
@@ -6656,7 +6680,7 @@ linebuffer_setlen (linebuffer *lbp, int toksize)
/* Like malloc but get fatal error if memory is exhausted. */
static PTR
-xmalloc (unsigned int size)
+xmalloc (size_t size)
{
PTR result = (PTR) malloc (size);
if (result == NULL)
@@ -6665,7 +6689,7 @@ xmalloc (unsigned int size)
}
static PTR
-xrealloc (char *ptr, unsigned int size)
+xrealloc (char *ptr, size_t size)
{
PTR result = (PTR) realloc (ptr, size);
if (result == NULL)
diff --git a/lib-src/movemail.c b/lib-src/movemail.c
index d70c655adec..097bf23c202 100644
--- a/lib-src/movemail.c
+++ b/lib-src/movemail.c
@@ -325,11 +325,10 @@ main (int argc, char **argv)
if (desc < 0)
{
int mkstemp_errno = errno;
- char *message = (char *) xmalloc (strlen (tempname) + 50);
- sprintf (message, "creating %s, which would become the lock file",
- tempname);
+ error ("error while creating what would become the lock file",
+ 0, 0);
errno = mkstemp_errno;
- pfatal_with_name (message);
+ pfatal_with_name (tempname);
}
close (desc);
diff --git a/lib-src/update-game-score.c b/lib-src/update-game-score.c
index 2a89379aefe..9fba51a33de 100644
--- a/lib-src/update-game-score.c
+++ b/lib-src/update-game-score.c
@@ -35,6 +35,7 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
#include <unistd.h>
#include <errno.h>
+#include <limits.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
@@ -128,19 +129,13 @@ lose_syserr (const char *msg)
static char *
get_user_id (void)
{
- char *name;
struct passwd *buf = getpwuid (getuid ());
if (!buf)
{
- int count = 1;
- int uid = (int) getuid ();
- int tuid = uid;
- while (tuid /= 10)
- count++;
- name = malloc (count+1);
- if (!name)
- return NULL;
- sprintf (name, "%d", uid);
+ long uid = getuid ();
+ char *name = malloc (sizeof uid * CHAR_BIT / 3 + 1);
+ if (name)
+ sprintf (name, "%ld", uid);
return name;
}
return buf->pw_name;
diff --git a/src/ChangeLog b/src/ChangeLog
index ceed28a7a7f..1de15f4796e 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,5 +1,110 @@
2011-08-29 Paul Eggert <eggert@cs.ucla.edu>
+ sprintf-related integer and memory overflow issues.
+
+ * doprnt.c (doprnt): Support printing ptrdiff_t and intmax_t values.
+ (esprintf, esnprintf, exprintf, evxprintf): New functions.
+ * keyboard.c (command_loop_level): Now EMACS_INT, not int.
+ (cmd_error): kbd macro iterations count is now EMACS_INT, not int.
+ (modify_event_symbol): Do not assume that the length of
+ name_alist_or_stem is safe to alloca and fits in int.
+ (Fexecute_extended_command): Likewise for function name and binding.
+ (Frecursion_depth): Wrap around reliably on integer overflow.
+ * keymap.c (push_key_description): First arg is now EMACS_INT, not int,
+ since some callers pass EMACS_INT values.
+ (Fsingle_key_description): Don't crash if symbol name contains more
+ than MAX_ALLOCA bytes.
+ * minibuf.c (minibuf_level): Now EMACS_INT, not int.
+ (get_minibuffer): Arg is now EMACS_INT, not int.
+ * lisp.h (get_minibuffer, push_key_description): Reflect API changes.
+ (esprintf, esnprintf, exprintf, evxprintf): New decls.
+ * window.h (command_loop_level, minibuf_level): Reflect API changes.
+
+ * dbusbind.c (xd_signature, Fdbus_register_signal):
+ Do not overrun buffer; instead, report string overflow.
+
+ * dispnew.c (add_window_display_history): Don't overrun buffer.
+ Truncate instead; this is OK since it's just a log.
+
+ * editfns.c (Fcurrent_time_zone): Don't overrun buffer
+ even if the time zone offset is outlandishly large.
+ Don't mishandle offset == INT_MIN.
+
+ * emacs.c (main) [NS_IMPL_COCOA]: Don't overrun buffer
+ when creating daemon; the previous buffer-overflow check was incorrect.
+
+ * eval.c (verror): Simplify by rewriting in terms of evxprintf,
+ which has the guts of the old verror function.
+
+ * filelock.c (lock_file_1, lock_file): Don't blindly alloca long name;
+ use SAFE_ALLOCA instead. Use esprintf to avoid int-overflow issues.
+
+ * font.c: Include <float.h>, for DBL_MAX_10_EXP.
+ (font_unparse_xlfd): Don't blindly alloca long strings.
+ Don't assume XINT result fits in int, or that XFLOAT_DATA * 10
+ fits in int, when using sprintf. Use single snprintf to count
+ length of string rather than counting it via multiple sprintfs;
+ that's simpler and more reliable.
+ (APPEND_SPRINTF): New macro.
+ (font_unparse_fcname): Use it to avoid sprintf buffer overrun.
+ (generate_otf_features) [0 && HAVE_LIBOTF]: Use esprintf, not
+ sprintf, in case result does not fit in int.
+
+ * fontset.c (num_auto_fontsets): Now printmax_t, not int.
+ (fontset_from_font): Print it.
+
+ * frame.c (tty_frame_count): Now printmax_t, not int.
+ (make_terminal_frame, set_term_frame_name): Print it.
+ (x_report_frame_params): In X, window IDs are unsigned long,
+ not signed long, so print them as unsigned.
+ (validate_x_resource_name): Check for implausibly long names,
+ and don't assume name length fits in 'int'.
+ (x_get_resource_string): Don't blindly alloca invocation name;
+ use SAFE_ALLOCA. Use esprintf, not sprintf, in case result does
+ not fit in int.
+
+ * gtkutil.c: Include <float.h>, for DBL_MAX_10_EXP.
+ (xg_check_special_colors, xg_set_geometry):
+ Make sprintf buffers a bit bigger, to avoid potential buffer overrun.
+
+ * lread.c (dir_warning): Don't blindly alloca buffer; use SAFE_ALLOCA.
+ Use esprintf, not sprintf, in case result does not fit in int.
+
+ * macros.c (executing_kbd_macro_iterations): Now EMACS_INT, not int.
+ (Fend_kbd_macro): Don't mishandle MOST_NEGATIVE_FIXNUM by treating
+ it as a large positive number.
+ (Fexecute_kbd_macro): Don't assume repeat count fits in int.
+ * macros.h (executing_kbd_macro_iterations): Now EMACS_INT, not int.
+
+ * nsterm.m ((NSSize)windowWillResize): Use esprintf, not sprintf,
+ in case result does not fit in int.
+
+ * print.c (float_to_string): Detect width overflow more reliably.
+ (print_object): Make sprintf buffer a bit bigger, to avoid potential
+ buffer overrun. Don't assume list length fits in 'int'. Treat
+ print length of 0 as 0, not as infinity; to be consistent with other
+ uses of print length in this function. Don't overflow print length
+ index. Don't assume hash table size fits in 'long', or that
+ vectorlike size fits in 'unsigned long'.
+
+ * process.c (make_process): Use printmax_t, not int, to format
+ process-name gensyms.
+
+ * term.c (produce_glyphless_glyph): Make sprintf buffer a bit bigger
+ to avoid potential buffer overrun.
+
+ * xfaces.c (x_update_menu_appearance): Don't overrun buffer
+ if X resource line is longer than 512 bytes.
+
+ * xfns.c (x_window): Make sprintf buffer a bit bigger
+ to avoid potential buffer overrun.
+
+ * xterm.c (x_io_error_quitter): Don't overrun sprintf buffer.
+
+ * xterm.h (x_check_errors): Add ATTRIBUTE_FORMAT_PRINTF.
+
+2011-08-29 Paul Eggert <eggert@cs.ucla.edu>
+
* image.c (parse_image_spec): Check for nonnegative, not for positive,
when checking :margin (Bug#9390).
(IMAGE_NON_NEGATIVE_INTEGER_VALUE_OR_PAIR):
diff --git a/src/dbusbind.c b/src/dbusbind.c
index 4828f4e968d..005d521c1db 100644
--- a/src/dbusbind.c
+++ b/src/dbusbind.c
@@ -271,6 +271,7 @@ xd_signature (char *signature, unsigned int dtype, unsigned int parent_type, Lis
{
unsigned int subtype;
Lisp_Object elt;
+ char const *subsig;
char x[DBUS_MAXIMUM_SIGNATURE_LENGTH];
elt = object;
@@ -328,12 +329,13 @@ xd_signature (char *signature, unsigned int dtype, unsigned int parent_type, Lis
if (NILP (elt))
{
subtype = DBUS_TYPE_STRING;
- strcpy (x, DBUS_TYPE_STRING_AS_STRING);
+ subsig = DBUS_TYPE_STRING_AS_STRING;
}
else
{
subtype = XD_OBJECT_TO_DBUS_TYPE (CAR_SAFE (elt));
xd_signature (x, subtype, dtype, CAR_SAFE (XD_NEXT_VALUE (elt)));
+ subsig = x;
}
/* If the element type is DBUS_TYPE_SIGNATURE, and this is the
@@ -342,7 +344,7 @@ xd_signature (char *signature, unsigned int dtype, unsigned int parent_type, Lis
if ((subtype == DBUS_TYPE_SIGNATURE)
&& STRINGP (CAR_SAFE (XD_NEXT_VALUE (elt)))
&& NILP (CDR_SAFE (XD_NEXT_VALUE (elt))))
- strcpy (x, SSDATA (CAR_SAFE (XD_NEXT_VALUE (elt))));
+ subsig = SSDATA (CAR_SAFE (XD_NEXT_VALUE (elt)));
while (!NILP (elt))
{
@@ -351,7 +353,10 @@ xd_signature (char *signature, unsigned int dtype, unsigned int parent_type, Lis
elt = CDR_SAFE (XD_NEXT_VALUE (elt));
}
- sprintf (signature, "%c%s", dtype, x);
+ if (esnprintf (signature, DBUS_MAXIMUM_SIGNATURE_LENGTH,
+ "%c%s", dtype, subsig)
+ == DBUS_MAXIMUM_SIGNATURE_LENGTH - 1)
+ string_overflow ();
break;
case DBUS_TYPE_VARIANT:
@@ -2026,7 +2031,7 @@ usage: (dbus-register-signal BUS SERVICE PATH INTERFACE SIGNAL HANDLER &rest ARG
DBusConnection *connection;
ptrdiff_t i;
char rule[DBUS_MAXIMUM_MATCH_RULE_LENGTH];
- char x[DBUS_MAXIMUM_MATCH_RULE_LENGTH];
+ int rulelen;
DBusError derror;
/* Check parameters. */
@@ -2071,34 +2076,32 @@ usage: (dbus-register-signal BUS SERVICE PATH INTERFACE SIGNAL HANDLER &rest ARG
connection = xd_initialize (bus, TRUE);
/* Create a rule to receive related signals. */
- sprintf (rule,
- "type='signal',interface='%s',member='%s'",
- SDATA (interface),
- SDATA (signal));
+ rulelen = esnprintf (rule, sizeof rule,
+ "type='signal',interface='%s',member='%s'",
+ SDATA (interface),
+ SDATA (signal));
/* Add unique name and path to the rule if they are non-nil. */
if (!NILP (uname))
- {
- sprintf (x, ",sender='%s'", SDATA (uname));
- strcat (rule, x);
- }
+ rulelen += esnprintf (rule + rulelen, sizeof rule - rulelen,
+ ",sender='%s'", SDATA (uname));
if (!NILP (path))
- {
- sprintf (x, ",path='%s'", SDATA (path));
- strcat (rule, x);
- }
+ rulelen += esnprintf (rule + rulelen, sizeof rule - rulelen,
+ ",path='%s'", SDATA (path));
/* Add arguments to the rule if they are non-nil. */
for (i = 6; i < nargs; ++i)
if (!NILP (args[i]))
{
CHECK_STRING (args[i]);
- sprintf (x, ",arg%"pD"d='%s'", i - 6,
- SDATA (args[i]));
- strcat (rule, x);
+ rulelen += esnprintf (rule + rulelen, sizeof rule - rulelen,
+ ",arg%"pD"d='%s'", i - 6, SDATA (args[i]));
}
+ if (rulelen == sizeof rule - 1)
+ string_overflow ();
+
/* Add the rule to the bus. */
dbus_error_init (&derror);
dbus_bus_add_match (connection, rule, &derror);
diff --git a/src/dispnew.c b/src/dispnew.c
index e96583e0025..0cc888b4b7a 100644
--- a/src/dispnew.c
+++ b/src/dispnew.c
@@ -272,15 +272,16 @@ add_window_display_history (struct window *w, const char *msg, int paused_p)
buf = redisplay_history[history_idx].trace;
++history_idx;
- sprintf (buf, "%"pMu": window %p (`%s')%s\n",
- history_tick++,
- w,
- ((BUFFERP (w->buffer)
- && STRINGP (BVAR (XBUFFER (w->buffer), name)))
- ? SSDATA (BVAR (XBUFFER (w->buffer), name))
- : "???"),
- paused_p ? " ***paused***" : "");
- strcat (buf, msg);
+ esnprintf (buf, sizeof redisplay_history[0].trace,
+ "%"pMu": window %p (`%s')%s\n%s",
+ history_tick++,
+ w,
+ ((BUFFERP (w->buffer)
+ && STRINGP (BVAR (XBUFFER (w->buffer), name)))
+ ? SSDATA (BVAR (XBUFFER (w->buffer), name))
+ : "???"),
+ paused_p ? " ***paused***" : "",
+ msg);
}
diff --git a/src/doprnt.c b/src/doprnt.c
index 79f9f36e461..dae1dab04d7 100644
--- a/src/doprnt.c
+++ b/src/doprnt.c
@@ -70,9 +70,9 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
%<flags><width><precision><length>character
where flags is [+ -0], width is [0-9]+, precision is .[0-9]+, and length
- is empty or l or the value of the pI macro. Also, %% in a format
- stands for a single % in the output. A % that does not introduce a
- valid %-sequence causes undefined behavior.
+ is empty or l or the value of the pD or pI or pMd (sans "d") macros.
+ Also, %% in a format stands for a single % in the output. A % that
+ does not introduce a valid %-sequence causes undefined behavior.
The + flag character inserts a + before any positive number, while a space
inserts a space before any positive number; these flags only affect %d, %o,
@@ -85,8 +85,10 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
modifier: it is supported for %d, %o, and %x conversions of integral
arguments, must immediately precede the conversion specifier, and means that
the respective argument is to be treated as `long int' or `unsigned long
- int'. Similarly, the value of the pI macro means to use EMACS_INT or
- EMACS_UINT and the empty length modifier means `int' or `unsigned int'.
+ int'. Similarly, the value of the pD macro means to use ptrdiff_t,
+ the value of the pI macro means to use EMACS_INT or EMACS_UINT, the
+ value of the pMd etc. macros means to use intmax_t or uintmax_t,
+ and the empty length modifier means `int' or `unsigned int'.
The width specifier supplies a lower limit for the length of the printed
representation. The padding, if any, normally goes on the left, but it goes
@@ -173,8 +175,17 @@ doprnt (char *buffer, ptrdiff_t bufsize, const char *format,
{
ptrdiff_t size_bound = 0;
EMACS_INT width; /* Columns occupied by STRING on display. */
- int long_flag = 0;
- int pIlen = sizeof pI - 1;
+ enum {
+ pDlen = sizeof pD - 1,
+ pIlen = sizeof pI - 1,
+ pMlen = sizeof pMd - 2
+ };
+ enum {
+ no_modifier, long_modifier, pD_modifier, pI_modifier, pM_modifier
+ } length_modifier = no_modifier;
+ static char const modifier_len[] = { 0, 1, pDlen, pIlen, pMlen };
+ int maxmlen = max (max (1, pDlen), max (pIlen, pMlen));
+ int mlen;
fmt++;
/* Copy this one %-spec into fmtcpy. */
@@ -213,19 +224,26 @@ doprnt (char *buffer, ptrdiff_t bufsize, const char *format,
fmt++;
}
- if (0 < pIlen && pIlen <= format_end - fmt
- && memcmp (fmt, pI, pIlen) == 0)
+ /* Check for the length modifiers in textual length order, so
+ that longer modifiers override shorter ones. */
+ for (mlen = 1; mlen <= maxmlen; mlen++)
{
- long_flag = 2;
- memcpy (string, fmt + 1, pIlen);
- string += pIlen;
- fmt += pIlen;
- }
- else if (fmt < format_end && *fmt == 'l')
- {
- long_flag = 1;
- *string++ = *++fmt;
+ if (format_end - fmt < mlen)
+ break;
+ if (mlen == 1 && *fmt == 'l')
+ length_modifier = long_modifier;
+ if (mlen == pDlen && memcmp (fmt, pD, pDlen) == 0)
+ length_modifier = pD_modifier;
+ if (mlen == pIlen && memcmp (fmt, pI, pIlen) == 0)
+ length_modifier = pI_modifier;
+ if (mlen == pMlen && memcmp (fmt, pMd, pMlen) == 0)
+ length_modifier = pM_modifier;
}
+
+ mlen = modifier_len[length_modifier];
+ memcpy (string, fmt + 1, mlen);
+ string += mlen;
+ fmt += mlen;
*string = 0;
/* Make the size bound large enough to handle floating point formats
@@ -252,55 +270,78 @@ doprnt (char *buffer, ptrdiff_t bufsize, const char *format,
/* case 'b': */
case 'l':
case 'd':
- {
- int i;
- long l;
-
- if (1 < long_flag)
+ switch (length_modifier)
+ {
+ case no_modifier:
{
- EMACS_INT ll = va_arg (ap, EMACS_INT);
- sprintf (sprintf_buffer, fmtcpy, ll);
+ int v = va_arg (ap, int);
+ sprintf (sprintf_buffer, fmtcpy, v);
}
- else if (long_flag)
+ break;
+ case long_modifier:
{
- l = va_arg(ap, long);
- sprintf (sprintf_buffer, fmtcpy, l);
+ long v = va_arg (ap, long);
+ sprintf (sprintf_buffer, fmtcpy, v);
}
- else
+ break;
+ case pD_modifier:
+ signed_pD_modifier:
{
- i = va_arg(ap, int);
- sprintf (sprintf_buffer, fmtcpy, i);
+ ptrdiff_t v = va_arg (ap, ptrdiff_t);
+ sprintf (sprintf_buffer, fmtcpy, v);
}
- /* Now copy into final output, truncating as necessary. */
- string = sprintf_buffer;
- goto doit;
- }
+ break;
+ case pI_modifier:
+ {
+ EMACS_INT v = va_arg (ap, EMACS_INT);
+ sprintf (sprintf_buffer, fmtcpy, v);
+ }
+ break;
+ case pM_modifier:
+ {
+ intmax_t v = va_arg (ap, intmax_t);
+ sprintf (sprintf_buffer, fmtcpy, v);
+ }
+ break;
+ }
+ /* Now copy into final output, truncating as necessary. */
+ string = sprintf_buffer;
+ goto doit;
case 'o':
case 'x':
- {
- unsigned u;
- unsigned long ul;
-
- if (1 < long_flag)
+ switch (length_modifier)
+ {
+ case no_modifier:
{
- EMACS_UINT ull = va_arg (ap, EMACS_UINT);
- sprintf (sprintf_buffer, fmtcpy, ull);
+ unsigned v = va_arg (ap, unsigned);
+ sprintf (sprintf_buffer, fmtcpy, v);
}
- else if (long_flag)
+ break;
+ case long_modifier:
{
- ul = va_arg(ap, unsigned long);
- sprintf (sprintf_buffer, fmtcpy, ul);
+ unsigned long v = va_arg (ap, unsigned long);
+ sprintf (sprintf_buffer, fmtcpy, v);
}
- else
+ break;
+ case pD_modifier:
+ goto signed_pD_modifier;
+ case pI_modifier:
{
- u = va_arg(ap, unsigned);
- sprintf (sprintf_buffer, fmtcpy, u);
+ EMACS_UINT v = va_arg (ap, EMACS_UINT);
+ sprintf (sprintf_buffer, fmtcpy, v);
}
- /* Now copy into final output, truncating as necessary. */
- string = sprintf_buffer;
- goto doit;
- }
+ break;
+ case pM_modifier:
+ {
+ uintmax_t v = va_arg (ap, uintmax_t);
+ sprintf (sprintf_buffer, fmtcpy, v);
+ }
+ break;
+ }
+ /* Now copy into final output, truncating as necessary. */
+ string = sprintf_buffer;
+ goto doit;
case 'f':
case 'e':
@@ -426,3 +467,82 @@ doprnt (char *buffer, ptrdiff_t bufsize, const char *format,
SAFE_FREE ();
return bufptr - buffer;
}
+
+/* Format to an unbounded buffer BUF. This is like sprintf, except it
+ is not limited to returning an 'int' so it doesn't have a silly 2
+ GiB limit on typical 64-bit hosts. However, it is limited to the
+ Emacs-style formats that doprnt supports.
+
+ Return the number of bytes put into BUF, excluding the terminating
+ '\0'. */
+ptrdiff_t
+esprintf (char *buf, char const *format, ...)
+{
+ ptrdiff_t nbytes;
+ va_list ap;
+ va_start (ap, format);
+ nbytes = doprnt (buf, TYPE_MAXIMUM (ptrdiff_t), format, 0, ap);
+ va_end (ap);
+ return nbytes;
+}
+
+/* Format to a buffer BUF of positive size BUFSIZE. This is like
+ snprintf, except it is not limited to returning an 'int' so it
+ doesn't have a silly 2 GiB limit on typical 64-bit hosts. However,
+ it is limited to the Emacs-style formats that doprnt supports, and
+ BUFSIZE must be positive.
+
+ Return the number of bytes put into BUF, excluding the terminating
+ '\0'. Unlike snprintf, always return a nonnegative value less than
+ BUFSIZE; if the output is truncated, return BUFSIZE - 1, which is
+ the length of the truncated output. */
+ptrdiff_t
+esnprintf (char *buf, ptrdiff_t bufsize, char const *format, ...)
+{
+ ptrdiff_t nbytes;
+ va_list ap;
+ va_start (ap, format);
+ nbytes = doprnt (buf, bufsize, format, 0, ap);
+ va_end (ap);
+ return nbytes;
+}
+
+/* Format to buffer *BUF of positive size *BUFSIZE, reallocating *BUF
+ and updating *BUFSIZE if the buffer is too small, and otherwise
+ behaving line esprintf. When reallocating, free *BUF unless it is
+ equal to NONHEAPBUF, and if BUFSIZE_MAX is nonnegative then signal
+ memory exhaustion instead of growing the buffer size past
+ BUFSIZE_MAX. */
+ptrdiff_t
+exprintf (char **buf, ptrdiff_t *bufsize,
+ char const *nonheapbuf, ptrdiff_t bufsize_max,
+ char const *format, ...)
+{
+ ptrdiff_t nbytes;
+ va_list ap;
+ va_start (ap, format);
+ nbytes = evxprintf (buf, bufsize, nonheapbuf, bufsize_max, format, ap);
+ va_end (ap);
+ return nbytes;
+}
+
+/* Act like exprintf, except take a va_list. */
+ptrdiff_t
+evxprintf (char **buf, ptrdiff_t *bufsize,
+ char const *nonheapbuf, ptrdiff_t bufsize_max,
+ char const *format, va_list ap)
+{
+ for (;;)
+ {
+ ptrdiff_t nbytes;
+ va_list ap_copy;
+ va_copy (ap_copy, ap);
+ nbytes = doprnt (*buf, *bufsize, format, 0, ap_copy);
+ va_end (ap_copy);
+ if (nbytes < *bufsize - 1)
+ return nbytes;
+ if (*buf != nonheapbuf)
+ xfree (*buf);
+ *buf = xpalloc (NULL, bufsize, 1, bufsize_max, 1);
+ }
+}
diff --git a/src/editfns.c b/src/editfns.c
index 6759016766f..580298c6e7d 100644
--- a/src/editfns.c
+++ b/src/editfns.c
@@ -2014,7 +2014,7 @@ the data it can't find. */)
{
int offset = tm_diff (t, &gmt);
char *s = 0;
- char buf[6];
+ char buf[sizeof "+00" + INT_STRLEN_BOUND (int)];
#ifdef HAVE_TM_ZONE
if (t->tm_zone)
@@ -2029,7 +2029,8 @@ the data it can't find. */)
if (!s)
{
/* No local time zone name is available; use "+-NNNN" instead. */
- int am = (offset < 0 ? -offset : offset) / 60;
+ int m = offset / 60;
+ int am = offset < 0 ? - m : m;
sprintf (buf, "%c%02d%02d", (offset < 0 ? '-' : '+'), am/60, am%60);
s = buf;
}
diff --git a/src/emacs.c b/src/emacs.c
index 7039f063dc2..2c6af6b5431 100644
--- a/src/emacs.c
+++ b/src/emacs.c
@@ -1068,15 +1068,17 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem
if (!dname_arg || !strchr (dname_arg, '\n'))
{ /* In orig, child: now exec w/special daemon name. */
char fdStr[80];
+ int fdStrlen =
+ snprintf (fdStr, sizeof fdStr,
+ "--daemon=\n%d,%d\n%s", daemon_pipe[0],
+ daemon_pipe[1], dname_arg ? dname_arg : "");
- if (dname_arg && strlen (dname_arg) > 70)
+ if (! (0 <= fdStrlen && fdStrlen < sizeof fdStr))
{
fprintf (stderr, "daemon: child name too long\n");
exit (1);
}
- sprintf (fdStr, "--daemon=\n%d,%d\n%s", daemon_pipe[0],
- daemon_pipe[1], dname_arg ? dname_arg : "");
argv[skip_args] = fdStr;
execv (argv[0], argv);
diff --git a/src/eval.c b/src/eval.c
index e722b53fb72..f2407cede31 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -1951,35 +1951,11 @@ verror (const char *m, va_list ap)
char buf[4000];
ptrdiff_t size = sizeof buf;
ptrdiff_t size_max = STRING_BYTES_BOUND + 1;
- char const *m_end = m + strlen (m);
char *buffer = buf;
ptrdiff_t used;
Lisp_Object string;
- while (1)
- {
- va_list ap_copy;
- va_copy (ap_copy, ap);
- used = doprnt (buffer, size, m, m_end, ap_copy);
- va_end (ap_copy);
-
- /* Note: the -1 below is because `doprnt' returns the number of bytes
- excluding the terminating null byte, and it always terminates with a
- null byte, even when producing a truncated message. */
- if (used < size - 1)
- break;
- if (size <= size_max / 2)
- size *= 2;
- else if (size < size_max)
- size = size_max;
- else
- break; /* and leave the message truncated */
-
- if (buffer != buf)
- xfree (buffer);
- buffer = (char *) xmalloc (size);
- }
-
+ used = evxprintf (&buffer, &size, buf, size_max, m, ap);
string = make_string (buffer, used);
if (buffer != buf)
xfree (buffer);
diff --git a/src/filelock.c b/src/filelock.c
index c28ee7837fa..7235c862ef0 100644
--- a/src/filelock.c
+++ b/src/filelock.c
@@ -341,6 +341,9 @@ lock_file_1 (char *lfname, int force)
const char *user_name;
const char *host_name;
char *lock_info_str;
+ ptrdiff_t lock_info_size;
+ int symlink_errno;
+ USE_SAFE_ALLOCA;
/* Call this first because it can GC. */
boot = get_boot_time ();
@@ -353,17 +356,14 @@ lock_file_1 (char *lfname, int force)
host_name = SSDATA (Fsystem_name ());
else
host_name = "";
- lock_info_str = (char *)alloca (strlen (user_name) + strlen (host_name)
- + 2 * INT_STRLEN_BOUND (printmax_t)
- + sizeof "@.:");
+ lock_info_size = (strlen (user_name) + strlen (host_name)
+ + 2 * INT_STRLEN_BOUND (printmax_t)
+ + sizeof "@.:");
+ SAFE_ALLOCA (lock_info_str, char *, lock_info_size);
pid = getpid ();
- if (boot)
- sprintf (lock_info_str, "%s@%s.%"pMd":%"pMd,
- user_name, host_name, pid, boot);
- else
- sprintf (lock_info_str, "%s@%s.%"pMd,
- user_name, host_name, pid);
+ esprintf (lock_info_str, boot ? "%s@%s.%"pMd":%"pMd : "%s@%s.%"pMd,
+ user_name, host_name, pid, boot);
err = symlink (lock_info_str, lfname);
if (errno == EEXIST && force)
@@ -372,6 +372,9 @@ lock_file_1 (char *lfname, int force)
err = symlink (lock_info_str, lfname);
}
+ symlink_errno = errno;
+ SAFE_FREE ();
+ errno = symlink_errno;
return err == 0;
}
@@ -541,9 +544,11 @@ lock_file (Lisp_Object fn)
{
register Lisp_Object attack, orig_fn, encoded_fn;
register char *lfname, *locker;
+ ptrdiff_t locker_size;
lock_info_type lock_info;
printmax_t pid;
struct gcpro gcpro1;
+ USE_SAFE_ALLOCA;
/* Don't do locking while dumping Emacs.
Uncompressing wtmp files uses call-process, which does not work
@@ -580,15 +585,17 @@ lock_file (Lisp_Object fn)
return;
/* Else consider breaking the lock */
- locker = (char *) alloca (strlen (lock_info.user) + strlen (lock_info.host)
- + INT_STRLEN_BOUND (printmax_t)
- + sizeof "@ (pid )");
+ locker_size = (strlen (lock_info.user) + strlen (lock_info.host)
+ + INT_STRLEN_BOUND (printmax_t)
+ + sizeof "@ (pid )");
+ SAFE_ALLOCA (locker, char *, locker_size);
pid = lock_info.pid;
- sprintf (locker, "%s@%s (pid %"pMd")",
- lock_info.user, lock_info.host, pid);
+ esprintf (locker, "%s@%s (pid %"pMd")",
+ lock_info.user, lock_info.host, pid);
FREE_LOCK_INFO (lock_info);
attack = call2 (intern ("ask-user-about-lock"), fn, build_string (locker));
+ SAFE_FREE ();
if (!NILP (attack))
/* User says take the lock */
{
diff --git a/src/font.c b/src/font.c
index 5f8d22157d6..1609a2cc9ff 100644
--- a/src/font.c
+++ b/src/font.c
@@ -21,6 +21,7 @@ You should have received a copy of the GNU General Public License
along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
#include <config.h>
+#include <float.h>
#include <stdio.h>
#include <ctype.h>
#include <setjmp.h>
@@ -1180,7 +1181,7 @@ font_unparse_xlfd (Lisp_Object font, int pixel_size, char *name, int nbytes)
char *p;
const char *f[XLFD_REGISTRY_INDEX + 1];
Lisp_Object val;
- int i, j, len = 0;
+ int i, j, len;
font_assert (FONTP (font));
@@ -1195,9 +1196,9 @@ font_unparse_xlfd (Lisp_Object font, int pixel_size, char *name, int nbytes)
if (NILP (val))
{
if (j == XLFD_REGISTRY_INDEX)
- f[j] = "*-*", len += 4;
+ f[j] = "*-*";
else
- f[j] = "*", len += 2;
+ f[j] = "*";
}
else
{
@@ -1207,21 +1208,15 @@ font_unparse_xlfd (Lisp_Object font, int pixel_size, char *name, int nbytes)
&& ! strchr (SSDATA (val), '-'))
{
/* Change "jisx0208*" and "jisx0208" to "jisx0208*-*". */
- if (SDATA (val)[SBYTES (val) - 1] == '*')
- {
- f[j] = p = alloca (SBYTES (val) + 3);
- sprintf (p, "%s-*", SDATA (val));
- len += SBYTES (val) + 3;
- }
- else
- {
- f[j] = p = alloca (SBYTES (val) + 4);
- sprintf (p, "%s*-*", SDATA (val));
- len += SBYTES (val) + 4;
- }
+ ptrdiff_t alloc = SBYTES (val) + 4;
+ if (nbytes <= alloc)
+ return -1;
+ f[j] = p = alloca (alloc);
+ sprintf (p, "%s%s-*", SDATA (val),
+ "*" + (SDATA (val)[SBYTES (val) - 1] == '*'));
}
else
- f[j] = SSDATA (val), len += SBYTES (val) + 1;
+ f[j] = SSDATA (val);
}
}
@@ -1230,11 +1225,11 @@ font_unparse_xlfd (Lisp_Object font, int pixel_size, char *name, int nbytes)
{
val = font_style_symbolic (font, i, 0);
if (NILP (val))
- f[j] = "*", len += 2;
+ f[j] = "*";
else
{
val = SYMBOL_NAME (val);
- f[j] = SSDATA (val), len += SBYTES (val) + 1;
+ f[j] = SSDATA (val);
}
}
@@ -1242,64 +1237,62 @@ font_unparse_xlfd (Lisp_Object font, int pixel_size, char *name, int nbytes)
font_assert (NUMBERP (val) || NILP (val));
if (INTEGERP (val))
{
- i = XINT (val);
- if (i <= 0)
- i = pixel_size;
- if (i > 0)
+ EMACS_INT v = XINT (val);
+ if (v <= 0)
+ v = pixel_size;
+ if (v > 0)
{
- f[XLFD_PIXEL_INDEX] = p = alloca (22);
- len += sprintf (p, "%d-*", i) + 1;
+ f[XLFD_PIXEL_INDEX] = p =
+ alloca (sizeof "-*" + INT_STRLEN_BOUND (EMACS_INT));
+ sprintf (p, "%"pI"d-*", v);
}
else
- f[XLFD_PIXEL_INDEX] = "*-*", len += 4;
+ f[XLFD_PIXEL_INDEX] = "*-*";
}
else if (FLOATP (val))
{
- i = XFLOAT_DATA (val) * 10;
- f[XLFD_PIXEL_INDEX] = p = alloca (12);
- len += sprintf (p, "*-%d", i) + 1;
+ double v = XFLOAT_DATA (val) * 10;
+ f[XLFD_PIXEL_INDEX] = p = alloca (sizeof "*-" + 1 + DBL_MAX_10_EXP + 1);
+ sprintf (p, "*-%.0f", v);
}
else
- f[XLFD_PIXEL_INDEX] = "*-*", len += 4;
+ f[XLFD_PIXEL_INDEX] = "*-*";
if (INTEGERP (AREF (font, FONT_DPI_INDEX)))
{
- i = XINT (AREF (font, FONT_DPI_INDEX));
- f[XLFD_RESX_INDEX] = p = alloca (22);
- len += sprintf (p, "%d-%d", i, i) + 1;
+ EMACS_INT v = XINT (AREF (font, FONT_DPI_INDEX));
+ f[XLFD_RESX_INDEX] = p =
+ alloca (sizeof "-" + 2 * INT_STRLEN_BOUND (EMACS_INT));
+ sprintf (p, "%"pI"d-%"pI"d", v, v);
}
else
- f[XLFD_RESX_INDEX] = "*-*", len += 4;
+ f[XLFD_RESX_INDEX] = "*-*";
if (INTEGERP (AREF (font, FONT_SPACING_INDEX)))
{
- int spacing = XINT (AREF (font, FONT_SPACING_INDEX));
+ EMACS_INT spacing = XINT (AREF (font, FONT_SPACING_INDEX));
f[XLFD_SPACING_INDEX] = (spacing <= FONT_SPACING_PROPORTIONAL ? "p"
: spacing <= FONT_SPACING_DUAL ? "d"
: spacing <= FONT_SPACING_MONO ? "m"
: "c");
- len += 2;
}
else
- f[XLFD_SPACING_INDEX] = "*", len += 2;
+ f[XLFD_SPACING_INDEX] = "*";
if (INTEGERP (AREF (font, FONT_AVGWIDTH_INDEX)))
{
- f[XLFD_AVGWIDTH_INDEX] = p = alloca (22);
- len += sprintf (p, "%"pI"d",
- XINT (AREF (font, FONT_AVGWIDTH_INDEX))) + 1;
+ f[XLFD_AVGWIDTH_INDEX] = p = alloca (INT_BUFSIZE_BOUND (EMACS_INT));
+ sprintf (p, "%"pI"d", XINT (AREF (font, FONT_AVGWIDTH_INDEX)));
}
else
- f[XLFD_AVGWIDTH_INDEX] = "*", len += 2;
- len++; /* for terminating '\0'. */
- if (len >= nbytes)
- return -1;
- return sprintf (name, "-%s-%s-%s-%s-%s-%s-%s-%s-%s-%s-%s",
+ f[XLFD_AVGWIDTH_INDEX] = "*";
+ len = snprintf (name, nbytes, "-%s-%s-%s-%s-%s-%s-%s-%s-%s-%s-%s",
f[XLFD_FOUNDRY_INDEX], f[XLFD_FAMILY_INDEX],
f[XLFD_WEIGHT_INDEX], f[XLFD_SLANT_INDEX],
f[XLFD_SWIDTH_INDEX], f[XLFD_ADSTYLE_INDEX],
f[XLFD_PIXEL_INDEX], f[XLFD_RESX_INDEX],
f[XLFD_SPACING_INDEX], f[XLFD_AVGWIDTH_INDEX],
f[XLFD_REGISTRY_INDEX]);
+ return len < nbytes ? len : -1;
}
/* Parse NAME (null terminated) and store information in FONT
@@ -1553,23 +1546,19 @@ int
font_unparse_fcname (Lisp_Object font, int pixel_size, char *name, int nbytes)
{
Lisp_Object family, foundry;
- Lisp_Object tail, val;
+ Lisp_Object val;
int point_size;
int i;
- ptrdiff_t len = 1;
char *p;
+ char *lim;
Lisp_Object styles[3];
const char *style_names[3] = { "weight", "slant", "width" };
- char work[256];
family = AREF (font, FONT_FAMILY_INDEX);
if (! NILP (family))
{
if (SYMBOLP (family))
- {
- family = SYMBOL_NAME (family);
- len += SBYTES (family);
- }
+ family = SYMBOL_NAME (family);
else
family = Qnil;
}
@@ -1580,7 +1569,6 @@ font_unparse_fcname (Lisp_Object font, int pixel_size, char *name, int nbytes)
if (XINT (val) != 0)
pixel_size = XINT (val);
point_size = -1;
- len += 21; /* for ":pixelsize=NUM" */
}
else
{
@@ -1588,80 +1576,54 @@ font_unparse_fcname (Lisp_Object font, int pixel_size, char *name, int nbytes)
abort ();
pixel_size = -1;
point_size = (int) XFLOAT_DATA (val);
- len += 11; /* for "-NUM" */
}
foundry = AREF (font, FONT_FOUNDRY_INDEX);
if (! NILP (foundry))
{
if (SYMBOLP (foundry))
- {
- foundry = SYMBOL_NAME (foundry);
- len += 9 + SBYTES (foundry); /* ":foundry=NAME" */
- }
+ foundry = SYMBOL_NAME (foundry);
else
foundry = Qnil;
}
for (i = 0; i < 3; i++)
- {
- styles[i] = font_style_symbolic (font, FONT_WEIGHT_INDEX + i, 0);
- if (! NILP (styles[i]))
- len += sprintf (work, ":%s=%s", style_names[i],
- SDATA (SYMBOL_NAME (styles[i])));
- }
+ styles[i] = font_style_symbolic (font, FONT_WEIGHT_INDEX + i, 0);
- if (INTEGERP (AREF (font, FONT_DPI_INDEX)))
- len += sprintf (work, ":dpi=%"pI"d", XINT (AREF (font, FONT_DPI_INDEX)));
- if (INTEGERP (AREF (font, FONT_SPACING_INDEX)))
- len += strlen (":spacing=100");
- if (INTEGERP (AREF (font, FONT_AVGWIDTH_INDEX)))
- len += strlen (":scalable=false"); /* or ":scalable=true" */
- for (tail = AREF (font, FONT_EXTRA_INDEX); CONSP (tail); tail = XCDR (tail))
- {
- Lisp_Object key = XCAR (XCAR (tail)), value = XCDR (XCAR (tail));
-
- len += SBYTES (SYMBOL_NAME (key)) + 1; /* for :KEY= */
- if (STRINGP (value))
- len += SBYTES (value);
- else if (INTEGERP (value))
- len += sprintf (work, "%"pI"d", XINT (value));
- else if (SYMBOLP (value))
- len += (NILP (value) ? 5 : 4); /* for "false" or "true" */
- }
-
- if (len > nbytes)
- return -1;
p = name;
+ lim = name + nbytes;
+# define APPEND_SNPRINTF(args) \
+ do { \
+ int len = snprintf args; \
+ if (! (0 <= len && len < lim - p)) \
+ return -1; \
+ p += len; \
+ } while (0)
if (! NILP (family))
- p += sprintf (p, "%s", SDATA (family));
+ APPEND_SNPRINTF ((p, lim - p, "%s", SSDATA (family)));
if (point_size > 0)
- {
- if (p == name)
- p += sprintf (p, "%d", point_size);
- else
- p += sprintf (p, "-%d", point_size);
- }
+ APPEND_SNPRINTF ((p, lim - p, "-%d" + (p == name), point_size));
else if (pixel_size > 0)
- p += sprintf (p, ":pixelsize=%d", pixel_size);
+ APPEND_SNPRINTF ((p, lim - p, ":pixelsize=%d", pixel_size));
if (! NILP (AREF (font, FONT_FOUNDRY_INDEX)))
- p += sprintf (p, ":foundry=%s",
- SDATA (SYMBOL_NAME (AREF (font, FONT_FOUNDRY_INDEX))));
+ APPEND_SNPRINTF ((p, lim - p, ":foundry=%s",
+ SSDATA (SYMBOL_NAME (AREF (font,
+ FONT_FOUNDRY_INDEX)))));
for (i = 0; i < 3; i++)
if (! NILP (styles[i]))
- p += sprintf (p, ":%s=%s", style_names[i],
- SDATA (SYMBOL_NAME (styles[i])));
+ APPEND_SNPRINTF ((p, lim - p, ":%s=%s", style_names[i],
+ SSDATA (SYMBOL_NAME (styles[i]))));
if (INTEGERP (AREF (font, FONT_DPI_INDEX)))
- p += sprintf (p, ":dpi=%"pI"d", XINT (AREF (font, FONT_DPI_INDEX)));
+ APPEND_SNPRINTF ((p, lim - p, ":dpi=%"pI"d",
+ XINT (AREF (font, FONT_DPI_INDEX))));
if (INTEGERP (AREF (font, FONT_SPACING_INDEX)))
- p += sprintf (p, ":spacing=%"pI"d", XINT (AREF (font, FONT_SPACING_INDEX)));
+ APPEND_SNPRINTF ((p, lim - p, ":spacing=%"pI"d",
+ XINT (AREF (font, FONT_SPACING_INDEX))));
if (INTEGERP (AREF (font, FONT_AVGWIDTH_INDEX)))
- {
- if (XINT (AREF (font, FONT_AVGWIDTH_INDEX)) == 0)
- p += sprintf (p, ":scalable=true");
- else
- p += sprintf (p, ":scalable=false");
- }
+ APPEND_SNPRINTF ((p, lim - p,
+ (XINT (AREF (font, FONT_AVGWIDTH_INDEX)) == 0
+ ? ":scalable=true"
+ : ":scalable=false")));
return (p - name);
}
@@ -1952,12 +1914,12 @@ generate_otf_features (Lisp_Object spec, char *features)
else if (! asterisk)
{
val = SYMBOL_NAME (val);
- p += sprintf (p, "%s", SDATA (val));
+ p += esprintf (p, "%s", SDATA (val));
}
else
{
val = SYMBOL_NAME (val);
- p += sprintf (p, "~%s", SDATA (val));
+ p += esprintf (p, "~%s", SDATA (val));
}
}
if (CONSP (spec))
diff --git a/src/fontset.c b/src/fontset.c
index c8ae1e74848..74a25a1ca04 100644
--- a/src/fontset.c
+++ b/src/fontset.c
@@ -1700,7 +1700,7 @@ FONT-SPEC is a vector, a cons, or a string. See the documentation of
static Lisp_Object auto_fontset_alist;
/* Number of automatically created fontsets. */
-static int num_auto_fontsets;
+static printmax_t num_auto_fontsets;
/* Retun a fontset synthesized from FONT-OBJECT. This is called from
x_new_font when FONT-OBJECT is used for the default ASCII font of a
@@ -1727,9 +1727,9 @@ fontset_from_font (Lisp_Object font_object)
alias = intern ("fontset-startup");
else
{
- char temp[32];
+ char temp[sizeof "fontset-auto" + INT_STRLEN_BOUND (printmax_t)];
- sprintf (temp, "fontset-auto%d", num_auto_fontsets - 1);
+ sprintf (temp, "fontset-auto%"pMd, num_auto_fontsets - 1);
alias = intern (temp);
}
fontset_spec = copy_font_spec (font_spec);
diff --git a/src/frame.c b/src/frame.c
index 711109a70c6..66b857a73e9 100644
--- a/src/frame.c
+++ b/src/frame.c
@@ -497,7 +497,7 @@ make_minibuffer_frame (void)
/* Construct a frame that refers to a terminal. */
-static int tty_frame_count;
+static printmax_t tty_frame_count;
struct frame *
make_initial_frame (void)
@@ -551,7 +551,7 @@ make_terminal_frame (struct terminal *terminal)
{
register struct frame *f;
Lisp_Object frame;
- char name[20];
+ char name[sizeof "F" + INT_STRLEN_BOUND (printmax_t)];
if (!terminal->name)
error ("Terminal is not live, can't create new frames on it");
@@ -562,7 +562,7 @@ make_terminal_frame (struct terminal *terminal)
Vframe_list = Fcons (frame, Vframe_list);
tty_frame_count++;
- sprintf (name, "F%d", tty_frame_count);
+ sprintf (name, "F%"pMd, tty_frame_count);
f->name = build_string (name);
f->visible = 1; /* FRAME_SET_VISIBLE wd set frame_garbaged. */
@@ -2074,7 +2074,7 @@ set_term_frame_name (struct frame *f, Lisp_Object name)
/* If NAME is nil, set the name to F<num>. */
if (NILP (name))
{
- char namebuf[20];
+ char namebuf[sizeof "F" + INT_STRLEN_BOUND (printmax_t)];
/* Check for no change needed in this very common case
before we do any consing. */
@@ -2083,7 +2083,7 @@ set_term_frame_name (struct frame *f, Lisp_Object name)
return;
tty_frame_count++;
- sprintf (namebuf, "F%d", tty_frame_count);
+ sprintf (namebuf, "F%"pMd, tty_frame_count);
name = build_string (namebuf);
}
else
@@ -3065,6 +3065,7 @@ x_report_frame_params (struct frame *f, Lisp_Object *alistptr)
{
char buf[16];
Lisp_Object tem;
+ unsigned long w;
/* Represent negative positions (off the top or left screen edge)
in a way that Fmodify_frame_parameters will understand correctly. */
@@ -3097,7 +3098,8 @@ x_report_frame_params (struct frame *f, Lisp_Object *alistptr)
for non-toolkit scroll bar.
ruler-mode.el depends on this. */
: Qnil));
- sprintf (buf, "%ld", (long) FRAME_X_WINDOW (f));
+ w = FRAME_X_WINDOW (f);
+ sprintf (buf, "%lu", w);
store_in_alist (alistptr, Qwindow_id,
build_string (buf));
#ifdef HAVE_X_WINDOWS
@@ -3105,7 +3107,10 @@ x_report_frame_params (struct frame *f, Lisp_Object *alistptr)
/* Tooltip frame may not have this widget. */
if (FRAME_X_OUTPUT (f)->widget)
#endif
- sprintf (buf, "%ld", (long) FRAME_OUTER_WINDOW (f));
+ {
+ w = FRAME_OUTER_WINDOW (f);
+ sprintf (buf, "%lu", w);
+ }
store_in_alist (alistptr, Qouter_window_id,
build_string (buf));
#endif
@@ -3576,13 +3581,13 @@ x_set_alpha (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
void
validate_x_resource_name (void)
{
- int len = 0;
+ ptrdiff_t len = 0;
/* Number of valid characters in the resource name. */
- int good_count = 0;
+ ptrdiff_t good_count = 0;
/* Number of invalid characters in the resource name. */
- int bad_count = 0;
+ ptrdiff_t bad_count = 0;
Lisp_Object new;
- int i;
+ ptrdiff_t i;
if (!STRINGP (Vx_resource_class))
Vx_resource_class = build_string (EMACS_CLASS);
@@ -3615,8 +3620,9 @@ validate_x_resource_name (void)
if (bad_count == 0)
return;
- /* If name is entirely invalid, or nearly so, use `emacs'. */
- if (good_count < 2)
+ /* If name is entirely invalid, or nearly so, or is so implausibly
+ large that alloca might not work, use `emacs'. */
+ if (good_count < 2 || MAX_ALLOCA - sizeof ".customization" < len)
{
Vx_resource_name = build_string ("emacs");
return;
@@ -3745,20 +3751,24 @@ x_get_resource_string (const char *attribute, const char *class)
{
char *name_key;
char *class_key;
+ char *result;
struct frame *sf = SELECTED_FRAME ();
+ ptrdiff_t invocation_namelen = SBYTES (Vinvocation_name);
+ USE_SAFE_ALLOCA;
/* Allocate space for the components, the dots which separate them,
and the final '\0'. */
- name_key = (char *) alloca (SBYTES (Vinvocation_name)
- + strlen (attribute) + 2);
+ SAFE_ALLOCA (name_key, char *, invocation_namelen + strlen (attribute) + 2);
class_key = (char *) alloca ((sizeof (EMACS_CLASS) - 1)
+ strlen (class) + 2);
- sprintf (name_key, "%s.%s", SSDATA (Vinvocation_name), attribute);
+ esprintf (name_key, "%s.%s", SSDATA (Vinvocation_name), attribute);
sprintf (class_key, "%s.%s", EMACS_CLASS, class);
- return x_get_string_resource (FRAME_X_DISPLAY_INFO (sf)->xrdb,
- name_key, class_key);
+ result = x_get_string_resource (FRAME_X_DISPLAY_INFO (sf)->xrdb,
+ name_key, class_key);
+ SAFE_FREE ();
+ return result;
}
#endif
diff --git a/src/gtkutil.c b/src/gtkutil.c
index c39119c8151..c154797735e 100644
--- a/src/gtkutil.c
+++ b/src/gtkutil.c
@@ -20,6 +20,7 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
#include <config.h>
#ifdef USE_GTK
+#include <float.h>
#include <signal.h>
#include <stdio.h>
#include <setjmp.h>
@@ -567,7 +568,7 @@ xg_check_special_colors (struct frame *f,
GtkStyleContext *gsty
= gtk_widget_get_style_context (FRAME_GTK_OUTER_WIDGET (f));
GdkRGBA col;
- char buf[64];
+ char buf[sizeof "rgbi://" + 3 * (DBL_MAX_10_EXP + sizeof "-1.000000" - 1)];
int state = GTK_STATE_FLAG_SELECTED|GTK_STATE_FLAG_FOCUSED;
if (get_fg)
gtk_style_context_get_color (gsty, state, &col);
@@ -797,7 +798,7 @@ xg_set_geometry (FRAME_PTR f)
int xneg = f->size_hint_flags & XNegative;
int top = f->top_pos;
int yneg = f->size_hint_flags & YNegative;
- char geom_str[32];
+ char geom_str[sizeof "=x--" + 4 * INT_STRLEN_BOUND (int)];
if (xneg)
left = -left;
diff --git a/src/keyboard.c b/src/keyboard.c
index ab93e0ccd24..51eac369e7c 100644
--- a/src/keyboard.c
+++ b/src/keyboard.c
@@ -196,7 +196,7 @@ int immediate_quit;
int quit_char;
/* Current depth in recursive edits. */
-int command_loop_level;
+EMACS_INT command_loop_level;
/* If not Qnil, this is a switch-frame event which we decided to put
off until the end of a key sequence. This should be read as the
@@ -998,7 +998,8 @@ static Lisp_Object
cmd_error (Lisp_Object data)
{
Lisp_Object old_level, old_length;
- char macroerror[50];
+ char macroerror[sizeof "After..kbd macro iterations: "
+ + INT_STRLEN_BOUND (EMACS_INT)];
#ifdef HAVE_WINDOW_SYSTEM
if (display_hourglass_p)
@@ -1010,7 +1011,7 @@ cmd_error (Lisp_Object data)
if (executing_kbd_macro_iterations == 1)
sprintf (macroerror, "After 1 kbd macro iteration: ");
else
- sprintf (macroerror, "After %d kbd macro iterations: ",
+ sprintf (macroerror, "After %"pI"d kbd macro iterations: ",
executing_kbd_macro_iterations);
}
else
@@ -6463,11 +6464,15 @@ modify_event_symbol (EMACS_INT symbol_num, unsigned int modifiers, Lisp_Object s
value = Fcdr_safe (Fassq (symbol_int, name_alist_or_stem));
else if (STRINGP (name_alist_or_stem))
{
- int len = SBYTES (name_alist_or_stem);
- char *buf = (char *) alloca (len + 50);
- sprintf (buf, "%s-%"pI"d", SDATA (name_alist_or_stem),
- XINT (symbol_int) + 1);
+ char *buf;
+ ptrdiff_t len = (SBYTES (name_alist_or_stem)
+ + sizeof "-" + INT_STRLEN_BOUND (EMACS_INT));
+ USE_SAFE_ALLOCA;
+ SAFE_ALLOCA (buf, char *, len);
+ esprintf (buf, "%s-%"pI"d", SDATA (name_alist_or_stem),
+ XINT (symbol_int) + 1);
value = intern (buf);
+ SAFE_FREE ();
}
else if (name_table != 0 && name_table[symbol_num])
value = intern (name_table[symbol_num]);
@@ -6483,7 +6488,7 @@ modify_event_symbol (EMACS_INT symbol_num, unsigned int modifiers, Lisp_Object s
if (NILP (value))
{
- char buf[20];
+ char buf[sizeof "key-" + INT_STRLEN_BOUND (EMACS_INT)];
sprintf (buf, "key-%"pI"d", symbol_num);
value = intern (buf);
}
@@ -10382,19 +10387,21 @@ give to the command you invoke, if it asks for an argument. */)
char *newmessage;
int message_p = push_message ();
int count = SPECPDL_INDEX ();
+ ptrdiff_t newmessage_len, newmessage_alloc;
+ USE_SAFE_ALLOCA;
record_unwind_protect (pop_message_unwind, Qnil);
binding = Fkey_description (bindings, Qnil);
-
- newmessage
- = (char *) alloca (SCHARS (SYMBOL_NAME (function))
- + SBYTES (binding)
- + 100);
- sprintf (newmessage, "You can run the command `%s' with %s",
- SDATA (SYMBOL_NAME (function)),
- SDATA (binding));
+ newmessage_alloc =
+ (sizeof "You can run the command `' with "
+ + SBYTES (SYMBOL_NAME (function)) + SBYTES (binding));
+ SAFE_ALLOCA (newmessage, char *, newmessage_alloc);
+ newmessage_len =
+ esprintf (newmessage, "You can run the command `%s' with %s",
+ SDATA (SYMBOL_NAME (function)),
+ SDATA (binding));
message2 (newmessage,
- strlen (newmessage),
+ newmessage_len,
STRING_MULTIBYTE (binding));
if (NUMBERP (Vsuggest_key_bindings))
waited = sit_for (Vsuggest_key_bindings, 0, 2);
@@ -10404,6 +10411,7 @@ give to the command you invoke, if it asks for an argument. */)
if (!NILP (waited) && message_p)
restore_message ();
+ SAFE_FREE ();
unbind_to (count, Qnil);
}
}
@@ -10633,7 +10641,9 @@ DEFUN ("recursion-depth", Frecursion_depth, Srecursion_depth, 0, 0, 0,
(void)
{
Lisp_Object temp;
- XSETFASTINT (temp, command_loop_level + minibuf_level);
+ /* Wrap around reliably on integer overflow. */
+ EMACS_INT sum = (command_loop_level & INTMASK) + (minibuf_level & INTMASK);
+ XSETINT (temp, sum);
return temp;
}
diff --git a/src/keymap.c b/src/keymap.c
index 32b531daac4..4485080db21 100644
--- a/src/keymap.c
+++ b/src/keymap.c
@@ -2143,12 +2143,12 @@ spaces are put between sequence elements, etc. */)
char *
-push_key_description (register unsigned int c, register char *p, int force_multibyte)
+push_key_description (EMACS_INT ch, char *p, int force_multibyte)
{
- unsigned c2;
+ int c, c2;
/* Clear all the meaningless bits above the meta bit. */
- c &= meta_modifier | ~ - meta_modifier;
+ c = ch & (meta_modifier | ~ - meta_modifier);
c2 = c & ~(alt_modifier | ctrl_modifier | hyper_modifier
| meta_modifier | shift_modifier | super_modifier);
@@ -2283,10 +2283,15 @@ around function keys and event symbols. */)
{
if (NILP (no_angles))
{
- char *buffer
- = (char *) alloca (SBYTES (SYMBOL_NAME (key)) + 5);
- sprintf (buffer, "<%s>", SDATA (SYMBOL_NAME (key)));
- return build_string (buffer);
+ char *buffer;
+ Lisp_Object result;
+ USE_SAFE_ALLOCA;
+ SAFE_ALLOCA (buffer, char *,
+ sizeof "<>" + SBYTES (SYMBOL_NAME (key)));
+ esprintf (buffer, "<%s>", SDATA (SYMBOL_NAME (key)));
+ result = build_string (buffer);
+ SAFE_FREE ();
+ return result;
}
else
return Fsymbol_name (key);
diff --git a/src/lisp.h b/src/lisp.h
index 99555118047..2f6ec38f228 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -2895,6 +2895,16 @@ extern void syms_of_print (void);
/* Defined in doprnt.c */
extern ptrdiff_t doprnt (char *, ptrdiff_t, const char *, const char *,
va_list);
+extern ptrdiff_t esprintf (char *, char const *, ...)
+ ATTRIBUTE_FORMAT_PRINTF (2, 3);
+extern ptrdiff_t esnprintf (char *, ptrdiff_t, char const *, ...)
+ ATTRIBUTE_FORMAT_PRINTF (3, 4);
+extern ptrdiff_t exprintf (char **, ptrdiff_t *, char const *, ptrdiff_t,
+ char const *, ...)
+ ATTRIBUTE_FORMAT_PRINTF (5, 6);
+extern ptrdiff_t evxprintf (char **, ptrdiff_t *, char const *, ptrdiff_t,
+ char const *, va_list)
+ ATTRIBUTE_FORMAT_PRINTF (5, 0);
/* Defined in lread.c. */
extern Lisp_Object Qvariable_documentation, Qstandard_input;
@@ -3186,7 +3196,7 @@ EXFUN (Fread_minibuffer, 2);
EXFUN (Feval_minibuffer, 2);
EXFUN (Fread_string, 5);
EXFUN (Fassoc_string, 3);
-extern Lisp_Object get_minibuffer (int);
+extern Lisp_Object get_minibuffer (EMACS_INT);
extern void init_minibuf_once (void);
extern void syms_of_minibuf (void);
@@ -3250,7 +3260,7 @@ extern void force_auto_save_soon (void);
extern void init_keyboard (void);
extern void syms_of_keyboard (void);
extern void keys_of_keyboard (void);
-extern char *push_key_description (unsigned int, char *, int);
+extern char *push_key_description (EMACS_INT, char *, int);
/* Defined in indent.c */
diff --git a/src/lread.c b/src/lread.c
index d24da729df6..ec65e881b0e 100644
--- a/src/lread.c
+++ b/src/lread.c
@@ -4295,14 +4295,20 @@ init_lread (void)
void
dir_warning (const char *format, Lisp_Object dirname)
{
- char *buffer
- = (char *) alloca (SCHARS (dirname) + strlen (format) + 5);
-
fprintf (stderr, format, SDATA (dirname));
- sprintf (buffer, format, SDATA (dirname));
+
/* Don't log the warning before we've initialized!! */
if (initialized)
- message_dolog (buffer, strlen (buffer), 0, STRING_MULTIBYTE (dirname));
+ {
+ char *buffer;
+ ptrdiff_t message_len;
+ USE_SAFE_ALLOCA;
+ SAFE_ALLOCA (buffer, char *,
+ SBYTES (dirname) + strlen (format) - (sizeof "%s" - 1) + 1);
+ message_len = esprintf (buffer, format, SDATA (dirname));
+ message_dolog (buffer, message_len, 0, STRING_MULTIBYTE (dirname));
+ SAFE_FREE ();
+ }
}
void
diff --git a/src/macros.c b/src/macros.c
index f6cd3a3ccad..4ecf49834a1 100644
--- a/src/macros.c
+++ b/src/macros.c
@@ -35,7 +35,7 @@ static Lisp_Object Qkbd_macro_termination_hook;
This is not bound at each level,
so after an error, it describes the innermost interrupted macro. */
-int executing_kbd_macro_iterations;
+EMACS_INT executing_kbd_macro_iterations;
/* This is the macro that was executing.
This is not bound at each level,
@@ -175,11 +175,11 @@ each iteration of the macro. Iteration stops if LOOPFUNC returns nil. */)
if (XFASTINT (repeat) == 0)
Fexecute_kbd_macro (KVAR (current_kboard, Vlast_kbd_macro), repeat, loopfunc);
- else
+ else if (XINT (repeat) > 1)
{
XSETINT (repeat, XINT (repeat)-1);
- if (XINT (repeat) > 0)
- Fexecute_kbd_macro (KVAR (current_kboard, Vlast_kbd_macro), repeat, loopfunc);
+ Fexecute_kbd_macro (KVAR (current_kboard, Vlast_kbd_macro),
+ repeat, loopfunc);
}
return Qnil;
}
@@ -302,9 +302,9 @@ each iteration of the macro. Iteration stops if LOOPFUNC returns nil. */)
Lisp_Object final;
Lisp_Object tem;
int pdlcount = SPECPDL_INDEX ();
- int repeat = 1;
+ EMACS_INT repeat = 1;
struct gcpro gcpro1, gcpro2;
- int success_count = 0;
+ EMACS_INT success_count = 0;
executing_kbd_macro_iterations = 0;
diff --git a/src/macros.h b/src/macros.h
index 32a97e457e8..7a5d532fbb7 100644
--- a/src/macros.h
+++ b/src/macros.h
@@ -22,7 +22,7 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
This is not bound at each level,
so after an error, it describes the innermost interrupted macro. */
-extern int executing_kbd_macro_iterations;
+extern EMACS_INT executing_kbd_macro_iterations;
/* This is the macro that was executing.
This is not bound at each level,
@@ -42,4 +42,3 @@ extern void finalize_kbd_macro_chars (void);
/* Store a character into kbd macro being defined */
extern void store_kbd_macro_char (Lisp_Object);
-
diff --git a/src/minibuf.c b/src/minibuf.c
index eb564a10ec6..ad8f3ed8b86 100644
--- a/src/minibuf.c
+++ b/src/minibuf.c
@@ -49,7 +49,7 @@ static Lisp_Object minibuf_save_list;
/* Depth in minibuffer invocations. */
-int minibuf_level;
+EMACS_INT minibuf_level;
/* The maximum length of a minibuffer history. */
@@ -772,10 +772,10 @@ read_minibuf (Lisp_Object map, Lisp_Object initial, Lisp_Object prompt,
used for nonrecursive minibuffer invocations. */
Lisp_Object
-get_minibuffer (int depth)
+get_minibuffer (EMACS_INT depth)
{
Lisp_Object tail, num, buf;
- char name[24];
+ char name[sizeof " *Minibuf-*" + INT_STRLEN_BOUND (EMACS_INT)];
XSETFASTINT (num, depth);
tail = Fnthcdr (num, Vminibuffer_list);
@@ -787,7 +787,7 @@ get_minibuffer (int depth)
buf = Fcar (tail);
if (NILP (buf) || NILP (BVAR (XBUFFER (buf), name)))
{
- sprintf (name, " *Minibuf-%d*", depth);
+ sprintf (name, " *Minibuf-%"pI"d*", depth);
buf = Fget_buffer_create (build_string (name));
/* Although the buffer's name starts with a space, undo should be
diff --git a/src/nsterm.m b/src/nsterm.m
index 4c9574c35ba..827404a2974 100644
--- a/src/nsterm.m
+++ b/src/nsterm.m
@@ -5316,7 +5316,7 @@ ns_term_shutdown (int sig)
strcpy (old_title, t);
}
size_title = xmalloc (strlen (old_title) + 40);
- sprintf (size_title, "%s — (%d x %d)", old_title, cols, rows);
+ esprintf (size_title, "%s — (%d x %d)", old_title, cols, rows);
[window setTitle: [NSString stringWithUTF8String: size_title]];
[window display];
xfree (size_title);
diff --git a/src/print.c b/src/print.c
index 35f89860843..f47dc985e96 100644
--- a/src/print.c
+++ b/src/print.c
@@ -1016,12 +1016,15 @@ float_to_string (char *buf, double data)
{
width = 0;
do
- width = (width * 10) + (*cp++ - '0');
+ {
+ width = (width * 10) + (*cp++ - '0');
+ if (DBL_DIG < width)
+ goto lose;
+ }
while (*cp >= '0' && *cp <= '9');
/* A precision of zero is valid only for %f. */
- if (width > DBL_DIG
- || (width == 0 && *cp != 'f'))
+ if (width == 0 && *cp != 'f')
goto lose;
}
@@ -1314,7 +1317,9 @@ print_prune_string_charset (Lisp_Object string)
static void
print_object (Lisp_Object obj, register Lisp_Object printcharfun, int escapeflag)
{
- char buf[40];
+ char buf[max (sizeof "from..to..in " + 2 * INT_STRLEN_BOUND (EMACS_INT),
+ max (sizeof " . #" + INT_STRLEN_BOUND (printmax_t),
+ 40))];
QUIT;
@@ -1614,8 +1619,7 @@ print_object (Lisp_Object obj, register Lisp_Object printcharfun, int escapeflag
PRINTCHAR ('(');
{
- EMACS_INT print_length;
- int i;
+ printmax_t i, print_length;
Lisp_Object halftail = obj;
/* Negative values of print-length are invalid in CL.
@@ -1623,7 +1627,7 @@ print_object (Lisp_Object obj, register Lisp_Object printcharfun, int escapeflag
if (NATNUMP (Vprint_length))
print_length = XFASTINT (Vprint_length);
else
- print_length = 0;
+ print_length = TYPE_MAXIMUM (printmax_t);
i = 0;
while (CONSP (obj))
@@ -1634,7 +1638,7 @@ print_object (Lisp_Object obj, register Lisp_Object printcharfun, int escapeflag
/* Simple but imcomplete way. */
if (i != 0 && EQ (obj, halftail))
{
- sprintf (buf, " . #%d", i / 2);
+ sprintf (buf, " . #%"pMd, i / 2);
strout (buf, -1, -1, printcharfun);
goto end_of_list;
}
@@ -1654,15 +1658,16 @@ print_object (Lisp_Object obj, register Lisp_Object printcharfun, int escapeflag
}
}
- if (i++)
+ if (i)
PRINTCHAR (' ');
- if (print_length && i > print_length)
+ if (print_length <= i)
{
strout ("...", 3, 3, printcharfun);
goto end_of_list;
}
+ i++;
print_object (XCAR (obj), printcharfun, escapeflag);
obj = XCDR (obj);
@@ -1798,19 +1803,17 @@ print_object (Lisp_Object obj, register Lisp_Object printcharfun, int escapeflag
PRINTCHAR (' ');
strout (SDATA (SYMBOL_NAME (h->weak)), -1, -1, printcharfun);
PRINTCHAR (' ');
- sprintf (buf, "%ld/%ld", (long) h->count,
- (long) ASIZE (h->next));
+ sprintf (buf, "%"pI"d/%"pI"d", h->count, ASIZE (h->next));
strout (buf, -1, -1, printcharfun);
}
- sprintf (buf, " 0x%lx", (unsigned long) h);
+ sprintf (buf, " %p", h);
strout (buf, -1, -1, printcharfun);
PRINTCHAR ('>');
#endif
/* Implement a readable output, e.g.:
#s(hash-table size 2 test equal data (k1 v1 k2 v2)) */
/* Always print the size. */
- sprintf (buf, "#s(hash-table size %ld",
- (long) ASIZE (h->next));
+ sprintf (buf, "#s(hash-table size %"pI"d", ASIZE (h->next));
strout (buf, -1, -1, printcharfun);
if (!NILP (h->test))
@@ -2038,7 +2041,7 @@ print_object (Lisp_Object obj, register Lisp_Object printcharfun, int escapeflag
if (MISCP (obj))
sprintf (buf, "(MISC 0x%04x)", (int) XMISCTYPE (obj));
else if (VECTORLIKEP (obj))
- sprintf (buf, "(PVEC 0x%08lx)", (unsigned long) ASIZE (obj));
+ sprintf (buf, "(PVEC 0x%08"pI"x)", ASIZE (obj));
else
sprintf (buf, "(0x%02x)", (int) XTYPE (obj));
strout (buf, -1, -1, printcharfun);
diff --git a/src/process.c b/src/process.c
index a8088322147..058ad5f871f 100644
--- a/src/process.c
+++ b/src/process.c
@@ -616,8 +616,8 @@ make_process (Lisp_Object name)
{
register Lisp_Object val, tem, name1;
register struct Lisp_Process *p;
- char suffix[10];
- register int i;
+ char suffix[sizeof "<>" + INT_STRLEN_BOUND (printmax_t)];
+ printmax_t i;
p = allocate_process ();
@@ -651,7 +651,7 @@ make_process (Lisp_Object name)
{
tem = Fget_process (name1);
if (NILP (tem)) break;
- sprintf (suffix, "<%d>", i);
+ sprintf (suffix, "<%"pMd">", i);
name1 = concat2 (name, build_string (suffix));
}
name = name1;
diff --git a/src/term.c b/src/term.c
index 8672a2417c8..fb07fc4490e 100644
--- a/src/term.c
+++ b/src/term.c
@@ -1887,7 +1887,7 @@ produce_glyphless_glyph (struct it *it, int for_no_font, Lisp_Object acronym)
{
int face_id;
int len;
- char buf[9];
+ char buf[sizeof "\\x" + max (6, (sizeof it->c * CHAR_BIT + 3) / 4)];
char const *str = " ";
/* Get a face ID for the glyph by utilizing a cache (the same way as
diff --git a/src/window.h b/src/window.h
index 485734e907e..c6fa5e7a338 100644
--- a/src/window.h
+++ b/src/window.h
@@ -847,11 +847,11 @@ extern Lisp_Object echo_area_window;
/* Depth in recursive edits. */
-extern int command_loop_level;
+extern EMACS_INT command_loop_level;
/* Depth in minibuffer invocations. */
-extern int minibuf_level;
+extern EMACS_INT minibuf_level;
/* true if we should redraw the mode lines on the next redisplay. */
diff --git a/src/xfaces.c b/src/xfaces.c
index 431ca07b8df..47d55f4da4b 100644
--- a/src/xfaces.c
+++ b/src/xfaces.c
@@ -3549,6 +3549,8 @@ x_update_menu_appearance (struct frame *f)
rdb != NULL))
{
char line[512];
+ char *buf = line;
+ ptrdiff_t bufsize = sizeof line;
Lisp_Object lface = lface_from_face_name (f, Qmenu, 1);
struct face *face = FACE_FROM_ID (f, MENU_FACE_ID);
const char *myname = SSDATA (Vx_resource_name);
@@ -3561,24 +3563,25 @@ x_update_menu_appearance (struct frame *f)
if (STRINGP (LFACE_FOREGROUND (lface)))
{
- sprintf (line, "%s.%s*foreground: %s",
- myname, popup_path,
- SDATA (LFACE_FOREGROUND (lface)));
+ exprintf (&buf, &bufsize, line, -1, "%s.%s*foreground: %s",
+ myname, popup_path,
+ SDATA (LFACE_FOREGROUND (lface)));
XrmPutLineResource (&rdb, line);
- sprintf (line, "%s.pane.menubar*foreground: %s",
- myname, SDATA (LFACE_FOREGROUND (lface)));
+ exprintf (&buf, &bufsize, line, -1, "%s.pane.menubar*foreground: %s",
+ myname, SDATA (LFACE_FOREGROUND (lface)));
XrmPutLineResource (&rdb, line);
changed_p = 1;
}
if (STRINGP (LFACE_BACKGROUND (lface)))
{
- sprintf (line, "%s.%s*background: %s",
- myname, popup_path,
- SDATA (LFACE_BACKGROUND (lface)));
+ exprintf (&buf, &bufsize, line, -1, "%s.%s*background: %s",
+ myname, popup_path,
+ SDATA (LFACE_BACKGROUND (lface)));
XrmPutLineResource (&rdb, line);
- sprintf (line, "%s.pane.menubar*background: %s",
- myname, SDATA (LFACE_BACKGROUND (lface)));
+
+ exprintf (&buf, &bufsize, line, -1, "%s.pane.menubar*background: %s",
+ myname, SDATA (LFACE_BACKGROUND (lface)));
XrmPutLineResource (&rdb, line);
changed_p = 1;
}
@@ -3616,11 +3619,12 @@ x_update_menu_appearance (struct frame *f)
#else
char *fontsetname = SSDATA (xlfd);
#endif
- sprintf (line, "%s.pane.menubar*font%s: %s",
- myname, suffix, fontsetname);
+ exprintf (&buf, &bufsize, line, -1, "%s.pane.menubar*font%s: %s",
+ myname, suffix, fontsetname);
XrmPutLineResource (&rdb, line);
- sprintf (line, "%s.%s*font%s: %s",
- myname, popup_path, suffix, fontsetname);
+
+ exprintf (&buf, &bufsize, line, -1, "%s.%s*font%s: %s",
+ myname, popup_path, suffix, fontsetname);
XrmPutLineResource (&rdb, line);
changed_p = 1;
if (fontsetname != SSDATA (xlfd))
@@ -3630,6 +3634,9 @@ x_update_menu_appearance (struct frame *f)
if (changed_p && f->output_data.x->menubar_widget)
free_frame_menubar (f);
+
+ if (buf != line)
+ xfree (buf);
}
}
diff --git a/src/xfns.c b/src/xfns.c
index 9a3d5fcda83..194a8f063b7 100644
--- a/src/xfns.c
+++ b/src/xfns.c
@@ -2440,7 +2440,7 @@ x_window (struct frame *f, long window_prompting, int minibuffer_only)
/* Do some needed geometry management. */
{
ptrdiff_t len;
- char *tem, shell_position[32];
+ char *tem, shell_position[sizeof "=x++" + 4 * INT_STRLEN_BOUND (int)];
Arg gal[10];
int gac = 0;
int extra_borders = 0;
diff --git a/src/xterm.c b/src/xterm.c
index c07caec6c78..86393cf411f 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -7900,7 +7900,8 @@ x_io_error_quitter (Display *display)
{
char buf[256];
- sprintf (buf, "Connection lost to X server `%s'", DisplayString (display));
+ snprintf (buf, sizeof buf, "Connection lost to X server `%s'",
+ DisplayString (display));
x_connection_closed (display, buf);
return 0;
}
diff --git a/src/xterm.h b/src/xterm.h
index 30867656710..fe86a32d09f 100644
--- a/src/xterm.h
+++ b/src/xterm.h
@@ -955,7 +955,8 @@ XrmDatabase x_load_resources (Display *, const char *, const char *,
extern int x_text_icon (struct frame *, const char *);
extern int x_bitmap_icon (struct frame *, Lisp_Object);
extern void x_catch_errors (Display *);
-extern void x_check_errors (Display *, const char *);
+extern void x_check_errors (Display *, const char *)
+ ATTRIBUTE_FORMAT_PRINTF (2, 0);
extern int x_had_errors_p (Display *);
extern int x_catching_errors (void);
extern void x_uncatch_errors (void);