diff options
| author | Paul Eggert | 2011-08-29 08:43:34 -0700 |
|---|---|---|
| committer | Paul Eggert | 2011-08-29 08:43:34 -0700 |
| commit | 62f19c197d32e8773a284616d575686d87903b7d (patch) | |
| tree | 237de2d21e8a33f6821248890c01de7d83dbcba4 /src | |
| parent | 005d87bd2306e943a16b86c36d1482651d9932d8 (diff) | |
| download | emacs-62f19c197d32e8773a284616d575686d87903b7d.tar.gz emacs-62f19c197d32e8773a284616d575686d87903b7d.zip | |
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.
Diffstat (limited to 'src')
| -rw-r--r-- | src/ChangeLog | 22 | ||||
| -rw-r--r-- | src/doprnt.c | 224 | ||||
| -rw-r--r-- | src/keyboard.c | 46 | ||||
| -rw-r--r-- | src/keymap.c | 19 | ||||
| -rw-r--r-- | src/lisp.h | 14 | ||||
| -rw-r--r-- | src/minibuf.c | 8 | ||||
| -rw-r--r-- | src/window.h | 4 |
7 files changed, 252 insertions, 85 deletions
diff --git a/src/ChangeLog b/src/ChangeLog index bb2a0d20c1f..d60c57dfd53 100644 --- a/src/ChangeLog +++ b/src/ChangeLog | |||
| @@ -1,3 +1,25 @@ | |||
| 1 | 2011-08-29 Paul Eggert <eggert@cs.ucla.edu> | ||
| 2 | |||
| 3 | sprintf-related integer and memory overflow issues. | ||
| 4 | |||
| 5 | * doprnt.c (doprnt): Support printing ptrdiff_t and intmax_t values. | ||
| 6 | (esprintf, esnprintf, exprintf, evxprintf): New functions. | ||
| 7 | * keyboard.c (command_loop_level): Now EMACS_INT, not int. | ||
| 8 | (cmd_error): kbd macro iterations count is now EMACS_INT, not int. | ||
| 9 | (modify_event_symbol): Do not assume that the length of | ||
| 10 | name_alist_or_stem is safe to alloca and fits in int. | ||
| 11 | (Fexecute_extended_command): Likewise for function name and binding. | ||
| 12 | (Frecursion_depth): Wrap around reliably on integer overflow. | ||
| 13 | * keymap.c (push_key_description): First arg is now EMACS_INT, not int, | ||
| 14 | since some callers pass EMACS_INT values. | ||
| 15 | (Fsingle_key_description): Don't crash if symbol name contains more | ||
| 16 | than MAX_ALLOCA bytes. | ||
| 17 | * minibuf.c (minibuf_level): Now EMACS_INT, not int. | ||
| 18 | (get_minibuffer): Arg is now EMACS_INT, not int. | ||
| 19 | * lisp.h (get_minibuffer, push_key_description): Reflect API changes. | ||
| 20 | (esprintf, esnprintf, exprintf, evxprintf): New decls. | ||
| 21 | * window.h (command_loop_level, minibuf_level): Reflect API changes. | ||
| 22 | |||
| 1 | 2011-08-26 Paul Eggert <eggert@cs.ucla.edu> | 23 | 2011-08-26 Paul Eggert <eggert@cs.ucla.edu> |
| 2 | 24 | ||
| 3 | Integer and memory overflow issues (Bug#9196). | 25 | Integer and memory overflow issues (Bug#9196). |
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/>. */ | |||
| 70 | %<flags><width><precision><length>character | 70 | %<flags><width><precision><length>character |
| 71 | 71 | ||
| 72 | where flags is [+ -0], width is [0-9]+, precision is .[0-9]+, and length | 72 | where flags is [+ -0], width is [0-9]+, precision is .[0-9]+, and length |
| 73 | is empty or l or the value of the pI macro. Also, %% in a format | 73 | is empty or l or the value of the pD or pI or pMd (sans "d") macros. |
| 74 | stands for a single % in the output. A % that does not introduce a | 74 | Also, %% in a format stands for a single % in the output. A % that |
| 75 | valid %-sequence causes undefined behavior. | 75 | does not introduce a valid %-sequence causes undefined behavior. |
| 76 | 76 | ||
| 77 | The + flag character inserts a + before any positive number, while a space | 77 | The + flag character inserts a + before any positive number, while a space |
| 78 | inserts a space before any positive number; these flags only affect %d, %o, | 78 | 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/>. */ | |||
| 85 | modifier: it is supported for %d, %o, and %x conversions of integral | 85 | modifier: it is supported for %d, %o, and %x conversions of integral |
| 86 | arguments, must immediately precede the conversion specifier, and means that | 86 | arguments, must immediately precede the conversion specifier, and means that |
| 87 | the respective argument is to be treated as `long int' or `unsigned long | 87 | the respective argument is to be treated as `long int' or `unsigned long |
| 88 | int'. Similarly, the value of the pI macro means to use EMACS_INT or | 88 | int'. Similarly, the value of the pD macro means to use ptrdiff_t, |
| 89 | EMACS_UINT and the empty length modifier means `int' or `unsigned int'. | 89 | the value of the pI macro means to use EMACS_INT or EMACS_UINT, the |
| 90 | value of the pMd etc. macros means to use intmax_t or uintmax_t, | ||
| 91 | and the empty length modifier means `int' or `unsigned int'. | ||
| 90 | 92 | ||
| 91 | The width specifier supplies a lower limit for the length of the printed | 93 | The width specifier supplies a lower limit for the length of the printed |
| 92 | representation. The padding, if any, normally goes on the left, but it goes | 94 | 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, | |||
| 173 | { | 175 | { |
| 174 | ptrdiff_t size_bound = 0; | 176 | ptrdiff_t size_bound = 0; |
| 175 | EMACS_INT width; /* Columns occupied by STRING on display. */ | 177 | EMACS_INT width; /* Columns occupied by STRING on display. */ |
| 176 | int long_flag = 0; | 178 | enum { |
| 177 | int pIlen = sizeof pI - 1; | 179 | pDlen = sizeof pD - 1, |
| 180 | pIlen = sizeof pI - 1, | ||
| 181 | pMlen = sizeof pMd - 2 | ||
| 182 | }; | ||
| 183 | enum { | ||
| 184 | no_modifier, long_modifier, pD_modifier, pI_modifier, pM_modifier | ||
| 185 | } length_modifier = no_modifier; | ||
| 186 | static char const modifier_len[] = { 0, 1, pDlen, pIlen, pMlen }; | ||
| 187 | int maxmlen = max (max (1, pDlen), max (pIlen, pMlen)); | ||
| 188 | int mlen; | ||
| 178 | 189 | ||
| 179 | fmt++; | 190 | fmt++; |
| 180 | /* Copy this one %-spec into fmtcpy. */ | 191 | /* Copy this one %-spec into fmtcpy. */ |
| @@ -213,19 +224,26 @@ doprnt (char *buffer, ptrdiff_t bufsize, const char *format, | |||
| 213 | fmt++; | 224 | fmt++; |
| 214 | } | 225 | } |
| 215 | 226 | ||
| 216 | if (0 < pIlen && pIlen <= format_end - fmt | 227 | /* Check for the length modifiers in textual length order, so |
| 217 | && memcmp (fmt, pI, pIlen) == 0) | 228 | that longer modifiers override shorter ones. */ |
| 229 | for (mlen = 1; mlen <= maxmlen; mlen++) | ||
| 218 | { | 230 | { |
| 219 | long_flag = 2; | 231 | if (format_end - fmt < mlen) |
| 220 | memcpy (string, fmt + 1, pIlen); | 232 | break; |
| 221 | string += pIlen; | 233 | if (mlen == 1 && *fmt == 'l') |
| 222 | fmt += pIlen; | 234 | length_modifier = long_modifier; |
| 223 | } | 235 | if (mlen == pDlen && memcmp (fmt, pD, pDlen) == 0) |
| 224 | else if (fmt < format_end && *fmt == 'l') | 236 | length_modifier = pD_modifier; |
| 225 | { | 237 | if (mlen == pIlen && memcmp (fmt, pI, pIlen) == 0) |
| 226 | long_flag = 1; | 238 | length_modifier = pI_modifier; |
| 227 | *string++ = *++fmt; | 239 | if (mlen == pMlen && memcmp (fmt, pMd, pMlen) == 0) |
| 240 | length_modifier = pM_modifier; | ||
| 228 | } | 241 | } |
| 242 | |||
| 243 | mlen = modifier_len[length_modifier]; | ||
| 244 | memcpy (string, fmt + 1, mlen); | ||
| 245 | string += mlen; | ||
| 246 | fmt += mlen; | ||
| 229 | *string = 0; | 247 | *string = 0; |
| 230 | 248 | ||
| 231 | /* Make the size bound large enough to handle floating point formats | 249 | /* Make the size bound large enough to handle floating point formats |
| @@ -252,55 +270,78 @@ doprnt (char *buffer, ptrdiff_t bufsize, const char *format, | |||
| 252 | /* case 'b': */ | 270 | /* case 'b': */ |
| 253 | case 'l': | 271 | case 'l': |
| 254 | case 'd': | 272 | case 'd': |
| 255 | { | 273 | switch (length_modifier) |
| 256 | int i; | 274 | { |
| 257 | long l; | 275 | case no_modifier: |
| 258 | |||
| 259 | if (1 < long_flag) | ||
| 260 | { | 276 | { |
| 261 | EMACS_INT ll = va_arg (ap, EMACS_INT); | 277 | int v = va_arg (ap, int); |
| 262 | sprintf (sprintf_buffer, fmtcpy, ll); | 278 | sprintf (sprintf_buffer, fmtcpy, v); |
| 263 | } | 279 | } |
| 264 | else if (long_flag) | 280 | break; |
| 281 | case long_modifier: | ||
| 265 | { | 282 | { |
| 266 | l = va_arg(ap, long); | 283 | long v = va_arg (ap, long); |
| 267 | sprintf (sprintf_buffer, fmtcpy, l); | 284 | sprintf (sprintf_buffer, fmtcpy, v); |
| 268 | } | 285 | } |
| 269 | else | 286 | break; |
| 287 | case pD_modifier: | ||
| 288 | signed_pD_modifier: | ||
| 270 | { | 289 | { |
| 271 | i = va_arg(ap, int); | 290 | ptrdiff_t v = va_arg (ap, ptrdiff_t); |
| 272 | sprintf (sprintf_buffer, fmtcpy, i); | 291 | sprintf (sprintf_buffer, fmtcpy, v); |
| 273 | } | 292 | } |
| 274 | /* Now copy into final output, truncating as necessary. */ | 293 | break; |
| 275 | string = sprintf_buffer; | 294 | case pI_modifier: |
| 276 | goto doit; | 295 | { |
| 277 | } | 296 | EMACS_INT v = va_arg (ap, EMACS_INT); |
| 297 | sprintf (sprintf_buffer, fmtcpy, v); | ||
| 298 | } | ||
| 299 | break; | ||
| 300 | case pM_modifier: | ||
| 301 | { | ||
| 302 | intmax_t v = va_arg (ap, intmax_t); | ||
| 303 | sprintf (sprintf_buffer, fmtcpy, v); | ||
| 304 | } | ||
| 305 | break; | ||
| 306 | } | ||
| 307 | /* Now copy into final output, truncating as necessary. */ | ||
| 308 | string = sprintf_buffer; | ||
| 309 | goto doit; | ||
| 278 | 310 | ||
| 279 | case 'o': | 311 | case 'o': |
| 280 | case 'x': | 312 | case 'x': |
| 281 | { | 313 | switch (length_modifier) |
| 282 | unsigned u; | 314 | { |
| 283 | unsigned long ul; | 315 | case no_modifier: |
| 284 | |||
| 285 | if (1 < long_flag) | ||
| 286 | { | 316 | { |
| 287 | EMACS_UINT ull = va_arg (ap, EMACS_UINT); | 317 | unsigned v = va_arg (ap, unsigned); |
| 288 | sprintf (sprintf_buffer, fmtcpy, ull); | 318 | sprintf (sprintf_buffer, fmtcpy, v); |
| 289 | } | 319 | } |
| 290 | else if (long_flag) | 320 | break; |
| 321 | case long_modifier: | ||
| 291 | { | 322 | { |
| 292 | ul = va_arg(ap, unsigned long); | 323 | unsigned long v = va_arg (ap, unsigned long); |
| 293 | sprintf (sprintf_buffer, fmtcpy, ul); | 324 | sprintf (sprintf_buffer, fmtcpy, v); |
| 294 | } | 325 | } |
| 295 | else | 326 | break; |
| 327 | case pD_modifier: | ||
| 328 | goto signed_pD_modifier; | ||
| 329 | case pI_modifier: | ||
| 296 | { | 330 | { |
| 297 | u = va_arg(ap, unsigned); | 331 | EMACS_UINT v = va_arg (ap, EMACS_UINT); |
| 298 | sprintf (sprintf_buffer, fmtcpy, u); | 332 | sprintf (sprintf_buffer, fmtcpy, v); |
| 299 | } | 333 | } |
| 300 | /* Now copy into final output, truncating as necessary. */ | 334 | break; |
| 301 | string = sprintf_buffer; | 335 | case pM_modifier: |
| 302 | goto doit; | 336 | { |
| 303 | } | 337 | uintmax_t v = va_arg (ap, uintmax_t); |
| 338 | sprintf (sprintf_buffer, fmtcpy, v); | ||
| 339 | } | ||
| 340 | break; | ||
| 341 | } | ||
| 342 | /* Now copy into final output, truncating as necessary. */ | ||
| 343 | string = sprintf_buffer; | ||
| 344 | goto doit; | ||
| 304 | 345 | ||
| 305 | case 'f': | 346 | case 'f': |
| 306 | case 'e': | 347 | case 'e': |
| @@ -426,3 +467,82 @@ doprnt (char *buffer, ptrdiff_t bufsize, const char *format, | |||
| 426 | SAFE_FREE (); | 467 | SAFE_FREE (); |
| 427 | return bufptr - buffer; | 468 | return bufptr - buffer; |
| 428 | } | 469 | } |
| 470 | |||
| 471 | /* Format to an unbounded buffer BUF. This is like sprintf, except it | ||
| 472 | is not limited to returning an 'int' so it doesn't have a silly 2 | ||
| 473 | GiB limit on typical 64-bit hosts. However, it is limited to the | ||
| 474 | Emacs-style formats that doprnt supports. | ||
| 475 | |||
| 476 | Return the number of bytes put into BUF, excluding the terminating | ||
| 477 | '\0'. */ | ||
| 478 | ptrdiff_t | ||
| 479 | esprintf (char *buf, char const *format, ...) | ||
| 480 | { | ||
| 481 | ptrdiff_t nbytes; | ||
| 482 | va_list ap; | ||
| 483 | va_start (ap, format); | ||
| 484 | nbytes = doprnt (buf, TYPE_MAXIMUM (ptrdiff_t), format, 0, ap); | ||
| 485 | va_end (ap); | ||
| 486 | return nbytes; | ||
| 487 | } | ||
| 488 | |||
| 489 | /* Format to a buffer BUF of positive size BUFSIZE. This is like | ||
| 490 | snprintf, except it is not limited to returning an 'int' so it | ||
| 491 | doesn't have a silly 2 GiB limit on typical 64-bit hosts. However, | ||
| 492 | it is limited to the Emacs-style formats that doprnt supports, and | ||
| 493 | BUFSIZE must be positive. | ||
| 494 | |||
| 495 | Return the number of bytes put into BUF, excluding the terminating | ||
| 496 | '\0'. Unlike snprintf, always return a nonnegative value less than | ||
| 497 | BUFSIZE; if the output is truncated, return BUFSIZE - 1, which is | ||
| 498 | the length of the truncated output. */ | ||
| 499 | ptrdiff_t | ||
| 500 | esnprintf (char *buf, ptrdiff_t bufsize, char const *format, ...) | ||
| 501 | { | ||
| 502 | ptrdiff_t nbytes; | ||
| 503 | va_list ap; | ||
| 504 | va_start (ap, format); | ||
| 505 | nbytes = doprnt (buf, bufsize, format, 0, ap); | ||
| 506 | va_end (ap); | ||
| 507 | return nbytes; | ||
| 508 | } | ||
| 509 | |||
| 510 | /* Format to buffer *BUF of positive size *BUFSIZE, reallocating *BUF | ||
| 511 | and updating *BUFSIZE if the buffer is too small, and otherwise | ||
| 512 | behaving line esprintf. When reallocating, free *BUF unless it is | ||
| 513 | equal to NONHEAPBUF, and if BUFSIZE_MAX is nonnegative then signal | ||
| 514 | memory exhaustion instead of growing the buffer size past | ||
| 515 | BUFSIZE_MAX. */ | ||
| 516 | ptrdiff_t | ||
| 517 | exprintf (char **buf, ptrdiff_t *bufsize, | ||
| 518 | char const *nonheapbuf, ptrdiff_t bufsize_max, | ||
| 519 | char const *format, ...) | ||
| 520 | { | ||
| 521 | ptrdiff_t nbytes; | ||
| 522 | va_list ap; | ||
| 523 | va_start (ap, format); | ||
| 524 | nbytes = evxprintf (buf, bufsize, nonheapbuf, bufsize_max, format, ap); | ||
| 525 | va_end (ap); | ||
| 526 | return nbytes; | ||
| 527 | } | ||
| 528 | |||
| 529 | /* Act like exprintf, except take a va_list. */ | ||
| 530 | ptrdiff_t | ||
| 531 | evxprintf (char **buf, ptrdiff_t *bufsize, | ||
| 532 | char const *nonheapbuf, ptrdiff_t bufsize_max, | ||
| 533 | char const *format, va_list ap) | ||
| 534 | { | ||
| 535 | for (;;) | ||
| 536 | { | ||
| 537 | ptrdiff_t nbytes; | ||
| 538 | va_list ap_copy; | ||
| 539 | va_copy (ap_copy, ap); | ||
| 540 | nbytes = doprnt (*buf, *bufsize, format, 0, ap_copy); | ||
| 541 | va_end (ap_copy); | ||
| 542 | if (nbytes < *bufsize - 1) | ||
| 543 | return nbytes; | ||
| 544 | if (*buf != nonheapbuf) | ||
| 545 | xfree (*buf); | ||
| 546 | *buf = xpalloc (NULL, bufsize, 1, bufsize_max, 1); | ||
| 547 | } | ||
| 548 | } | ||
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; | |||
| 196 | int quit_char; | 196 | int quit_char; |
| 197 | 197 | ||
| 198 | /* Current depth in recursive edits. */ | 198 | /* Current depth in recursive edits. */ |
| 199 | int command_loop_level; | 199 | EMACS_INT command_loop_level; |
| 200 | 200 | ||
| 201 | /* If not Qnil, this is a switch-frame event which we decided to put | 201 | /* If not Qnil, this is a switch-frame event which we decided to put |
| 202 | off until the end of a key sequence. This should be read as the | 202 | off until the end of a key sequence. This should be read as the |
| @@ -998,7 +998,8 @@ static Lisp_Object | |||
| 998 | cmd_error (Lisp_Object data) | 998 | cmd_error (Lisp_Object data) |
| 999 | { | 999 | { |
| 1000 | Lisp_Object old_level, old_length; | 1000 | Lisp_Object old_level, old_length; |
| 1001 | char macroerror[50]; | 1001 | char macroerror[sizeof "After..kbd macro iterations: " |
| 1002 | + INT_STRLEN_BOUND (EMACS_INT)]; | ||
| 1002 | 1003 | ||
| 1003 | #ifdef HAVE_WINDOW_SYSTEM | 1004 | #ifdef HAVE_WINDOW_SYSTEM |
| 1004 | if (display_hourglass_p) | 1005 | if (display_hourglass_p) |
| @@ -1010,7 +1011,7 @@ cmd_error (Lisp_Object data) | |||
| 1010 | if (executing_kbd_macro_iterations == 1) | 1011 | if (executing_kbd_macro_iterations == 1) |
| 1011 | sprintf (macroerror, "After 1 kbd macro iteration: "); | 1012 | sprintf (macroerror, "After 1 kbd macro iteration: "); |
| 1012 | else | 1013 | else |
| 1013 | sprintf (macroerror, "After %d kbd macro iterations: ", | 1014 | sprintf (macroerror, "After %"pI"d kbd macro iterations: ", |
| 1014 | executing_kbd_macro_iterations); | 1015 | executing_kbd_macro_iterations); |
| 1015 | } | 1016 | } |
| 1016 | else | 1017 | else |
| @@ -6463,11 +6464,15 @@ modify_event_symbol (EMACS_INT symbol_num, unsigned int modifiers, Lisp_Object s | |||
| 6463 | value = Fcdr_safe (Fassq (symbol_int, name_alist_or_stem)); | 6464 | value = Fcdr_safe (Fassq (symbol_int, name_alist_or_stem)); |
| 6464 | else if (STRINGP (name_alist_or_stem)) | 6465 | else if (STRINGP (name_alist_or_stem)) |
| 6465 | { | 6466 | { |
| 6466 | int len = SBYTES (name_alist_or_stem); | 6467 | char *buf; |
| 6467 | char *buf = (char *) alloca (len + 50); | 6468 | ptrdiff_t len = (SBYTES (name_alist_or_stem) |
| 6468 | sprintf (buf, "%s-%"pI"d", SDATA (name_alist_or_stem), | 6469 | + sizeof "-" + INT_STRLEN_BOUND (EMACS_INT)); |
| 6469 | XINT (symbol_int) + 1); | 6470 | USE_SAFE_ALLOCA; |
| 6471 | SAFE_ALLOCA (buf, char *, len); | ||
| 6472 | esprintf (buf, "%s-%"pI"d", SDATA (name_alist_or_stem), | ||
| 6473 | XINT (symbol_int) + 1); | ||
| 6470 | value = intern (buf); | 6474 | value = intern (buf); |
| 6475 | SAFE_FREE (); | ||
| 6471 | } | 6476 | } |
| 6472 | else if (name_table != 0 && name_table[symbol_num]) | 6477 | else if (name_table != 0 && name_table[symbol_num]) |
| 6473 | value = intern (name_table[symbol_num]); | 6478 | value = intern (name_table[symbol_num]); |
| @@ -6483,7 +6488,7 @@ modify_event_symbol (EMACS_INT symbol_num, unsigned int modifiers, Lisp_Object s | |||
| 6483 | 6488 | ||
| 6484 | if (NILP (value)) | 6489 | if (NILP (value)) |
| 6485 | { | 6490 | { |
| 6486 | char buf[20]; | 6491 | char buf[sizeof "key-" + INT_STRLEN_BOUND (EMACS_INT)]; |
| 6487 | sprintf (buf, "key-%"pI"d", symbol_num); | 6492 | sprintf (buf, "key-%"pI"d", symbol_num); |
| 6488 | value = intern (buf); | 6493 | value = intern (buf); |
| 6489 | } | 6494 | } |
| @@ -10382,19 +10387,21 @@ give to the command you invoke, if it asks for an argument. */) | |||
| 10382 | char *newmessage; | 10387 | char *newmessage; |
| 10383 | int message_p = push_message (); | 10388 | int message_p = push_message (); |
| 10384 | int count = SPECPDL_INDEX (); | 10389 | int count = SPECPDL_INDEX (); |
| 10390 | ptrdiff_t newmessage_len, newmessage_alloc; | ||
| 10391 | USE_SAFE_ALLOCA; | ||
| 10385 | 10392 | ||
| 10386 | record_unwind_protect (pop_message_unwind, Qnil); | 10393 | record_unwind_protect (pop_message_unwind, Qnil); |
| 10387 | binding = Fkey_description (bindings, Qnil); | 10394 | binding = Fkey_description (bindings, Qnil); |
| 10388 | 10395 | newmessage_alloc = | |
| 10389 | newmessage | 10396 | (sizeof "You can run the command `' with " |
| 10390 | = (char *) alloca (SCHARS (SYMBOL_NAME (function)) | 10397 | + SBYTES (SYMBOL_NAME (function)) + SBYTES (binding)); |
| 10391 | + SBYTES (binding) | 10398 | SAFE_ALLOCA (newmessage, char *, newmessage_alloc); |
| 10392 | + 100); | 10399 | newmessage_len = |
| 10393 | sprintf (newmessage, "You can run the command `%s' with %s", | 10400 | esprintf (newmessage, "You can run the command `%s' with %s", |
| 10394 | SDATA (SYMBOL_NAME (function)), | 10401 | SDATA (SYMBOL_NAME (function)), |
| 10395 | SDATA (binding)); | 10402 | SDATA (binding)); |
| 10396 | message2 (newmessage, | 10403 | message2 (newmessage, |
| 10397 | strlen (newmessage), | 10404 | newmessage_len, |
| 10398 | STRING_MULTIBYTE (binding)); | 10405 | STRING_MULTIBYTE (binding)); |
| 10399 | if (NUMBERP (Vsuggest_key_bindings)) | 10406 | if (NUMBERP (Vsuggest_key_bindings)) |
| 10400 | waited = sit_for (Vsuggest_key_bindings, 0, 2); | 10407 | waited = sit_for (Vsuggest_key_bindings, 0, 2); |
| @@ -10404,6 +10411,7 @@ give to the command you invoke, if it asks for an argument. */) | |||
| 10404 | if (!NILP (waited) && message_p) | 10411 | if (!NILP (waited) && message_p) |
| 10405 | restore_message (); | 10412 | restore_message (); |
| 10406 | 10413 | ||
| 10414 | SAFE_FREE (); | ||
| 10407 | unbind_to (count, Qnil); | 10415 | unbind_to (count, Qnil); |
| 10408 | } | 10416 | } |
| 10409 | } | 10417 | } |
| @@ -10633,7 +10641,9 @@ DEFUN ("recursion-depth", Frecursion_depth, Srecursion_depth, 0, 0, 0, | |||
| 10633 | (void) | 10641 | (void) |
| 10634 | { | 10642 | { |
| 10635 | Lisp_Object temp; | 10643 | Lisp_Object temp; |
| 10636 | XSETFASTINT (temp, command_loop_level + minibuf_level); | 10644 | /* Wrap around reliably on integer overflow. */ |
| 10645 | EMACS_INT sum = (command_loop_level & INTMASK) + (minibuf_level & INTMASK); | ||
| 10646 | XSETINT (temp, sum); | ||
| 10637 | return temp; | 10647 | return temp; |
| 10638 | } | 10648 | } |
| 10639 | 10649 | ||
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. */) | |||
| 2143 | 2143 | ||
| 2144 | 2144 | ||
| 2145 | char * | 2145 | char * |
| 2146 | push_key_description (register unsigned int c, register char *p, int force_multibyte) | 2146 | push_key_description (EMACS_INT ch, char *p, int force_multibyte) |
| 2147 | { | 2147 | { |
| 2148 | unsigned c2; | 2148 | int c, c2; |
| 2149 | 2149 | ||
| 2150 | /* Clear all the meaningless bits above the meta bit. */ | 2150 | /* Clear all the meaningless bits above the meta bit. */ |
| 2151 | c &= meta_modifier | ~ - meta_modifier; | 2151 | c = ch & (meta_modifier | ~ - meta_modifier); |
| 2152 | c2 = c & ~(alt_modifier | ctrl_modifier | hyper_modifier | 2152 | c2 = c & ~(alt_modifier | ctrl_modifier | hyper_modifier |
| 2153 | | meta_modifier | shift_modifier | super_modifier); | 2153 | | meta_modifier | shift_modifier | super_modifier); |
| 2154 | 2154 | ||
| @@ -2283,10 +2283,15 @@ around function keys and event symbols. */) | |||
| 2283 | { | 2283 | { |
| 2284 | if (NILP (no_angles)) | 2284 | if (NILP (no_angles)) |
| 2285 | { | 2285 | { |
| 2286 | char *buffer | 2286 | char *buffer; |
| 2287 | = (char *) alloca (SBYTES (SYMBOL_NAME (key)) + 5); | 2287 | Lisp_Object result; |
| 2288 | sprintf (buffer, "<%s>", SDATA (SYMBOL_NAME (key))); | 2288 | USE_SAFE_ALLOCA; |
| 2289 | return build_string (buffer); | 2289 | SAFE_ALLOCA (buffer, char *, |
| 2290 | sizeof "<>" + SBYTES (SYMBOL_NAME (key))); | ||
| 2291 | esprintf (buffer, "<%s>", SDATA (SYMBOL_NAME (key))); | ||
| 2292 | result = build_string (buffer); | ||
| 2293 | SAFE_FREE (); | ||
| 2294 | return result; | ||
| 2290 | } | 2295 | } |
| 2291 | else | 2296 | else |
| 2292 | return Fsymbol_name (key); | 2297 | 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); | |||
| 2895 | /* Defined in doprnt.c */ | 2895 | /* Defined in doprnt.c */ |
| 2896 | extern ptrdiff_t doprnt (char *, ptrdiff_t, const char *, const char *, | 2896 | extern ptrdiff_t doprnt (char *, ptrdiff_t, const char *, const char *, |
| 2897 | va_list); | 2897 | va_list); |
| 2898 | extern ptrdiff_t esprintf (char *, char const *, ...) | ||
| 2899 | ATTRIBUTE_FORMAT_PRINTF (2, 3); | ||
| 2900 | extern ptrdiff_t esnprintf (char *, ptrdiff_t, char const *, ...) | ||
| 2901 | ATTRIBUTE_FORMAT_PRINTF (3, 4); | ||
| 2902 | extern ptrdiff_t exprintf (char **, ptrdiff_t *, char const *, ptrdiff_t, | ||
| 2903 | char const *, ...) | ||
| 2904 | ATTRIBUTE_FORMAT_PRINTF (5, 6); | ||
| 2905 | extern ptrdiff_t evxprintf (char **, ptrdiff_t *, char const *, ptrdiff_t, | ||
| 2906 | char const *, va_list) | ||
| 2907 | ATTRIBUTE_FORMAT_PRINTF (5, 0); | ||
| 2898 | 2908 | ||
| 2899 | /* Defined in lread.c. */ | 2909 | /* Defined in lread.c. */ |
| 2900 | extern Lisp_Object Qvariable_documentation, Qstandard_input; | 2910 | extern Lisp_Object Qvariable_documentation, Qstandard_input; |
| @@ -3186,7 +3196,7 @@ EXFUN (Fread_minibuffer, 2); | |||
| 3186 | EXFUN (Feval_minibuffer, 2); | 3196 | EXFUN (Feval_minibuffer, 2); |
| 3187 | EXFUN (Fread_string, 5); | 3197 | EXFUN (Fread_string, 5); |
| 3188 | EXFUN (Fassoc_string, 3); | 3198 | EXFUN (Fassoc_string, 3); |
| 3189 | extern Lisp_Object get_minibuffer (int); | 3199 | extern Lisp_Object get_minibuffer (EMACS_INT); |
| 3190 | extern void init_minibuf_once (void); | 3200 | extern void init_minibuf_once (void); |
| 3191 | extern void syms_of_minibuf (void); | 3201 | extern void syms_of_minibuf (void); |
| 3192 | 3202 | ||
| @@ -3250,7 +3260,7 @@ extern void force_auto_save_soon (void); | |||
| 3250 | extern void init_keyboard (void); | 3260 | extern void init_keyboard (void); |
| 3251 | extern void syms_of_keyboard (void); | 3261 | extern void syms_of_keyboard (void); |
| 3252 | extern void keys_of_keyboard (void); | 3262 | extern void keys_of_keyboard (void); |
| 3253 | extern char *push_key_description (unsigned int, char *, int); | 3263 | extern char *push_key_description (EMACS_INT, char *, int); |
| 3254 | 3264 | ||
| 3255 | 3265 | ||
| 3256 | /* Defined in indent.c */ | 3266 | /* Defined in indent.c */ |
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; | |||
| 49 | 49 | ||
| 50 | /* Depth in minibuffer invocations. */ | 50 | /* Depth in minibuffer invocations. */ |
| 51 | 51 | ||
| 52 | int minibuf_level; | 52 | EMACS_INT minibuf_level; |
| 53 | 53 | ||
| 54 | /* The maximum length of a minibuffer history. */ | 54 | /* The maximum length of a minibuffer history. */ |
| 55 | 55 | ||
| @@ -772,10 +772,10 @@ read_minibuf (Lisp_Object map, Lisp_Object initial, Lisp_Object prompt, | |||
| 772 | used for nonrecursive minibuffer invocations. */ | 772 | used for nonrecursive minibuffer invocations. */ |
| 773 | 773 | ||
| 774 | Lisp_Object | 774 | Lisp_Object |
| 775 | get_minibuffer (int depth) | 775 | get_minibuffer (EMACS_INT depth) |
| 776 | { | 776 | { |
| 777 | Lisp_Object tail, num, buf; | 777 | Lisp_Object tail, num, buf; |
| 778 | char name[24]; | 778 | char name[sizeof " *Minibuf-*" + INT_STRLEN_BOUND (EMACS_INT)]; |
| 779 | 779 | ||
| 780 | XSETFASTINT (num, depth); | 780 | XSETFASTINT (num, depth); |
| 781 | tail = Fnthcdr (num, Vminibuffer_list); | 781 | tail = Fnthcdr (num, Vminibuffer_list); |
| @@ -787,7 +787,7 @@ get_minibuffer (int depth) | |||
| 787 | buf = Fcar (tail); | 787 | buf = Fcar (tail); |
| 788 | if (NILP (buf) || NILP (BVAR (XBUFFER (buf), name))) | 788 | if (NILP (buf) || NILP (BVAR (XBUFFER (buf), name))) |
| 789 | { | 789 | { |
| 790 | sprintf (name, " *Minibuf-%d*", depth); | 790 | sprintf (name, " *Minibuf-%"pI"d*", depth); |
| 791 | buf = Fget_buffer_create (build_string (name)); | 791 | buf = Fget_buffer_create (build_string (name)); |
| 792 | 792 | ||
| 793 | /* Although the buffer's name starts with a space, undo should be | 793 | /* Although the buffer's name starts with a space, undo should be |
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; | |||
| 847 | 847 | ||
| 848 | /* Depth in recursive edits. */ | 848 | /* Depth in recursive edits. */ |
| 849 | 849 | ||
| 850 | extern int command_loop_level; | 850 | extern EMACS_INT command_loop_level; |
| 851 | 851 | ||
| 852 | /* Depth in minibuffer invocations. */ | 852 | /* Depth in minibuffer invocations. */ |
| 853 | 853 | ||
| 854 | extern int minibuf_level; | 854 | extern EMACS_INT minibuf_level; |
| 855 | 855 | ||
| 856 | /* true if we should redraw the mode lines on the next redisplay. */ | 856 | /* true if we should redraw the mode lines on the next redisplay. */ |
| 857 | 857 | ||