aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEli Zaretskii2011-04-23 13:33:28 +0300
committerEli Zaretskii2011-04-23 13:33:28 +0300
commite6c3da2065ac72cc4e1a2bef22d367cd75401892 (patch)
tree1f6fcbee1e12f63096d2221a89f5436b831862a9
parent4ffd0d6b569d252e4e807d4e9c9d6a5bd5b08640 (diff)
downloademacs-e6c3da2065ac72cc4e1a2bef22d367cd75401892.tar.gz
emacs-e6c3da2065ac72cc4e1a2bef22d367cd75401892.zip
Fix doprnt so it could be used safely in `verror'. (Bug#8435)
src/doprnt.c: Include limits.h. (SIZE_MAX): New macro. (doprnt): Return a size_t value. 2nd arg is now size_t. Many local variables are now size_t instead of int or unsigned. Improve overflow protection. Support `l' modifier for integer conversions. Support %l conversion. Don't assume an EMACS_INT argument for integer conversions and for %c. src/lisp.h (doprnt): Restore prototype. src/makefile.w32-in ($(BLD)/callint.$(O)): Depend on $(SRC)/character.h. src/Makefile.in (base_obj): Add back doprnt.o. src/deps.mk (doprnt.o): Add back prerequisites. (callint.o): Depend on character.h. src/eval.c (internal_lisp_condition_case): Include the handler representation in the error message. (verror): Call doprnt instead of vsnprintf. Fix an off-by-one bug when breaking from the loop. src/xdisp.c (vmessage): Call doprnt instead of vsnprintf. src/callint.c (Fcall_interactively): When displaying error message about invalid control letter, pass the character's codepoint, not a pointer to its multibyte form. Improve display of the character in octal and display also its hex code. src/character.c (char_string): Use %x to display the (unsigned) codepoint of an invalid character, to avoid displaying a bogus negative value. src/font.c (check_otf_features): Pass SDATA of SYMBOL_NAME to `error', not SYMBOL_NAME itself. src/coding.c (Fencode_sjis_char, Fencode_big5_char): Use %c for character arguments to `error'. src/charset.c (check_iso_charset_parameter): Fix incorrect argument to `error' in error message about FINAL_CHAR argument. Make sure FINAL_CHAR is a character, and use %c when it is passed as argument to `error'.
-rw-r--r--src/ChangeLog48
-rw-r--r--src/Makefile.in2
-rw-r--r--src/callint.c7
-rw-r--r--src/character.c2
-rw-r--r--src/charset.c10
-rw-r--r--src/coding.c4
-rw-r--r--src/deps.mk4
-rw-r--r--src/doprnt.c106
-rw-r--r--src/eval.c37
-rw-r--r--src/font.c6
-rw-r--r--src/lisp.h3
-rw-r--r--src/makefile.w32-in1
-rw-r--r--src/xdisp.c18
13 files changed, 165 insertions, 83 deletions
diff --git a/src/ChangeLog b/src/ChangeLog
index 0067163edbf..831fb6afcd0 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,5 +1,53 @@
12011-04-23 Eli Zaretskii <eliz@gnu.org> 12011-04-23 Eli Zaretskii <eliz@gnu.org>
2 2
3 Fix doprnt so it could be used again safely in `verror'. (Bug#8435)
4 * doprnt.c: Include limits.h.
5 (SIZE_MAX): New macro.
6 (doprnt): Return a size_t value. 2nd arg is now size_t. Many
7 local variables are now size_t instead of int or unsigned.
8 Improve overflow protection. Support `l' modifier for integer
9 conversions. Support %l conversion. Don't assume an EMACS_INT
10 argument for integer conversions and for %c.
11
12 * lisp.h (doprnt): Restore prototype.
13
14 * makefile.w32-in ($(BLD)/callint.$(O)): Depend on
15 $(SRC)/character.h.
16
17 * Makefile.in (base_obj): Add back doprnt.o.
18
19 * deps.mk (doprnt.o): Add back prerequisites.
20 (callint.o): Depend on character.h.
21
22 * eval.c (internal_lisp_condition_case): Include the handler
23 representation in the error message.
24 (verror): Call doprnt instead of vsnprintf. Fix an off-by-one bug
25 when breaking from the loop.
26
27 * xdisp.c (vmessage): Call doprnt instead of vsnprintf.
28
29 * callint.c (Fcall_interactively): When displaying error message
30 about invalid control letter, pass the character's codepoint, not
31 a pointer to its multibyte form. Improve display of the character
32 in octal and display also its hex code.
33
34 * character.c (char_string): Use %x to display the (unsigned)
35 codepoint of an invalid character, to avoid displaying a bogus
36 negative value.
37
38 * font.c (check_otf_features): Pass SDATA of SYMBOL_NAME to
39 `error', not SYMBOL_NAME itself.
40
41 * coding.c (Fencode_sjis_char, Fencode_big5_char): Use %c for
42 character arguments to `error'.
43
44 * charset.c (check_iso_charset_parameter): Fix incorrect argument
45 to `error' in error message about FINAL_CHAR argument. Make sure
46 FINAL_CHAR is a character, and use %c when it is passed as
47 argument to `error'.
48
492011-04-23 Eli Zaretskii <eliz@gnu.org>
50
3 * s/ms-w32.h (localtime): Redirect to sys_localtime. 51 * s/ms-w32.h (localtime): Redirect to sys_localtime.
4 52
5 * w32.c: Include <time.h>. 53 * w32.c: Include <time.h>.
diff --git a/src/Makefile.in b/src/Makefile.in
index 154d6abba4e..e1195968f7f 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -354,7 +354,7 @@ base_obj = dispnew.o frame.o scroll.o xdisp.o menu.o $(XMENU_OBJ) window.o \
354 syntax.o $(UNEXEC_OBJ) bytecode.o \ 354 syntax.o $(UNEXEC_OBJ) bytecode.o \
355 process.o gnutls.o callproc.o \ 355 process.o gnutls.o callproc.o \
356 region-cache.o sound.o atimer.o \ 356 region-cache.o sound.o atimer.o \
357 intervals.o textprop.o composite.o xml.o \ 357 doprnt.o intervals.o textprop.o composite.o xml.o \
358 $(MSDOS_OBJ) $(MSDOS_X_OBJ) $(NS_OBJ) $(CYGWIN_OBJ) $(FONT_OBJ) 358 $(MSDOS_OBJ) $(MSDOS_X_OBJ) $(NS_OBJ) $(CYGWIN_OBJ) $(FONT_OBJ)
359obj = $(base_obj) $(NS_OBJC_OBJ) 359obj = $(base_obj) $(NS_OBJC_OBJ)
360 360
diff --git a/src/callint.c b/src/callint.c
index e5ec3d7d931..cddd92c8a94 100644
--- a/src/callint.c
+++ b/src/callint.c
@@ -27,6 +27,7 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
27#include "keyboard.h" 27#include "keyboard.h"
28#include "window.h" 28#include "window.h"
29#include "keymap.h" 29#include "keymap.h"
30#include "character.h"
30 31
31Lisp_Object Qminus, Qplus; 32Lisp_Object Qminus, Qplus;
32Lisp_Object Qcall_interactively; 33Lisp_Object Qcall_interactively;
@@ -786,8 +787,10 @@ invoke it. If KEYS is omitted or nil, the return value of
786 if anyone tries to define one here. */ 787 if anyone tries to define one here. */
787 case '+': 788 case '+':
788 default: 789 default:
789 error ("Invalid control letter `%c' (%03o) in interactive calling string", 790 error ("Invalid control letter `%c' (#o%03o, #x%04x) in interactive calling string",
790 *tem, (unsigned char) *tem); 791 STRING_CHAR ((unsigned char *) tem),
792 (unsigned) STRING_CHAR ((unsigned char *) tem),
793 (unsigned) STRING_CHAR ((unsigned char *) tem));
791 } 794 }
792 795
793 if (varies[i] == 0) 796 if (varies[i] == 0)
diff --git a/src/character.c b/src/character.c
index 84eddeb2fc2..4087e8984d0 100644
--- a/src/character.c
+++ b/src/character.c
@@ -156,7 +156,7 @@ char_string (unsigned int c, unsigned char *p)
156 bytes = BYTE8_STRING (c, p); 156 bytes = BYTE8_STRING (c, p);
157 } 157 }
158 else 158 else
159 error ("Invalid character: %d", c); 159 error ("Invalid character: %x", c);
160 160
161 return bytes; 161 return bytes;
162} 162}
diff --git a/src/charset.c b/src/charset.c
index c4699dcb0a7..e7435c292e2 100644
--- a/src/charset.c
+++ b/src/charset.c
@@ -1436,7 +1436,7 @@ check_iso_charset_parameter (Lisp_Object dimension, Lisp_Object chars, Lisp_Obje
1436{ 1436{
1437 CHECK_NATNUM (dimension); 1437 CHECK_NATNUM (dimension);
1438 CHECK_NATNUM (chars); 1438 CHECK_NATNUM (chars);
1439 CHECK_NATNUM (final_char); 1439 CHECK_CHARACTER (final_char);
1440 1440
1441 if (XINT (dimension) > 3) 1441 if (XINT (dimension) > 3)
1442 error ("Invalid DIMENSION %"pEd", it should be 1, 2, or 3", 1442 error ("Invalid DIMENSION %"pEd", it should be 1, 2, or 3",
@@ -1444,12 +1444,8 @@ check_iso_charset_parameter (Lisp_Object dimension, Lisp_Object chars, Lisp_Obje
1444 if (XINT (chars) != 94 && XINT (chars) != 96) 1444 if (XINT (chars) != 94 && XINT (chars) != 96)
1445 error ("Invalid CHARS %"pEd", it should be 94 or 96", XINT (chars)); 1445 error ("Invalid CHARS %"pEd", it should be 94 or 96", XINT (chars));
1446 if (XINT (final_char) < '0' || XINT (final_char) > '~') 1446 if (XINT (final_char) < '0' || XINT (final_char) > '~')
1447 { 1447 error ("Invalid FINAL-CHAR %c, it should be `0'..`~'",
1448 unsigned char str[MAX_MULTIBYTE_LENGTH + 1]; 1448 (int)XINT (final_char));
1449 int len = CHAR_STRING (XINT (chars), str);
1450 str[len] = '\0';
1451 error ("Invalid FINAL-CHAR %s, it should be `0'..`~'", str);
1452 }
1453} 1449}
1454 1450
1455 1451
diff --git a/src/coding.c b/src/coding.c
index b49070e5e16..221ada51158 100644
--- a/src/coding.c
+++ b/src/coding.c
@@ -9071,7 +9071,7 @@ Return the corresponding code in SJIS. */)
9071 charset_list = CODING_ATTR_CHARSET_LIST (attrs); 9071 charset_list = CODING_ATTR_CHARSET_LIST (attrs);
9072 charset = char_charset (c, charset_list, &code); 9072 charset = char_charset (c, charset_list, &code);
9073 if (code == CHARSET_INVALID_CODE (charset)) 9073 if (code == CHARSET_INVALID_CODE (charset))
9074 error ("Can't encode by shift_jis encoding: %d", c); 9074 error ("Can't encode by shift_jis encoding: %c", c);
9075 JIS_TO_SJIS (code); 9075 JIS_TO_SJIS (code);
9076 9076
9077 return make_number (code); 9077 return make_number (code);
@@ -9142,7 +9142,7 @@ Return the corresponding character code in Big5. */)
9142 charset_list = CODING_ATTR_CHARSET_LIST (attrs); 9142 charset_list = CODING_ATTR_CHARSET_LIST (attrs);
9143 charset = char_charset (c, charset_list, &code); 9143 charset = char_charset (c, charset_list, &code);
9144 if (code == CHARSET_INVALID_CODE (charset)) 9144 if (code == CHARSET_INVALID_CODE (charset))
9145 error ("Can't encode by Big5 encoding: %d", c); 9145 error ("Can't encode by Big5 encoding: %c", c);
9146 9146
9147 return make_number (code); 9147 return make_number (code);
9148} 9148}
diff --git a/src/deps.mk b/src/deps.mk
index 2df1577ef78..8d0e0e69589 100644
--- a/src/deps.mk
+++ b/src/deps.mk
@@ -44,7 +44,8 @@ buffer.o: buffer.c buffer.h region-cache.h commands.h window.h \
44 $(INTERVALS_H) blockinput.h atimer.h systime.h character.h ../lib/unistd.h \ 44 $(INTERVALS_H) blockinput.h atimer.h systime.h character.h ../lib/unistd.h \
45 indent.h keyboard.h coding.h keymap.h frame.h lisp.h globals.h $(config_h) 45 indent.h keyboard.h coding.h keymap.h frame.h lisp.h globals.h $(config_h)
46callint.o: callint.c window.h commands.h buffer.h keymap.h globals.h msdos.h \ 46callint.o: callint.c window.h commands.h buffer.h keymap.h globals.h msdos.h \
47 keyboard.h dispextern.h systime.h coding.h composite.h lisp.h $(config_h) 47 keyboard.h dispextern.h systime.h coding.h composite.h lisp.h \
48 character.h $(config_h)
48callproc.o: callproc.c epaths.h buffer.h commands.h lisp.h $(config_h) \ 49callproc.o: callproc.c epaths.h buffer.h commands.h lisp.h $(config_h) \
49 process.h systty.h syssignal.h character.h coding.h ccl.h msdos.h \ 50 process.h systty.h syssignal.h character.h coding.h ccl.h msdos.h \
50 composite.h w32.h blockinput.h atimer.h systime.h frame.h termhooks.h \ 51 composite.h w32.h blockinput.h atimer.h systime.h frame.h termhooks.h \
@@ -82,6 +83,7 @@ dispnew.o: dispnew.c systime.h commands.h process.h frame.h coding.h \
82# doc.o's dependency on buildobj.h is in src/Makefile.in. 83# doc.o's dependency on buildobj.h is in src/Makefile.in.
83doc.o: doc.c lisp.h $(config_h) buffer.h keyboard.h keymap.h \ 84doc.o: doc.c lisp.h $(config_h) buffer.h keyboard.h keymap.h \
84 character.h systime.h coding.h composite.h ../lib/unistd.h globals.h 85 character.h systime.h coding.h composite.h ../lib/unistd.h globals.h
86doprnt.o: doprnt.c character.h lisp.h globals.h ../lib/unistd.h $(config_h)
85dosfns.o: buffer.h termchar.h termhooks.h frame.h blockinput.h window.h \ 87dosfns.o: buffer.h termchar.h termhooks.h frame.h blockinput.h window.h \
86 msdos.h dosfns.h dispextern.h charset.h coding.h atimer.h systime.h \ 88 msdos.h dosfns.h dispextern.h charset.h coding.h atimer.h systime.h \
87 lisp.h $(config_h) 89 lisp.h $(config_h)
diff --git a/src/doprnt.c b/src/doprnt.c
index 36eb272caae..f182529b801 100644
--- a/src/doprnt.c
+++ b/src/doprnt.c
@@ -30,6 +30,11 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
30 30
31#include <unistd.h> 31#include <unistd.h>
32 32
33#include <limits.h>
34#ifndef SIZE_MAX
35# define SIZE_MAX ((size_t) -1)
36#endif
37
33#include "lisp.h" 38#include "lisp.h"
34 39
35/* Since we use the macro CHAR_HEAD_P, we have to include this, but 40/* Since we use the macro CHAR_HEAD_P, we have to include this, but
@@ -51,8 +56,8 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
51 String arguments are passed as C strings. 56 String arguments are passed as C strings.
52 Integers are passed as C integers. */ 57 Integers are passed as C integers. */
53 58
54EMACS_INT 59size_t
55doprnt (char *buffer, register int bufsize, const char *format, 60doprnt (char *buffer, register size_t bufsize, const char *format,
56 const char *format_end, va_list ap) 61 const char *format_end, va_list ap)
57{ 62{
58 const char *fmt = format; /* Pointer into format string */ 63 const char *fmt = format; /* Pointer into format string */
@@ -62,15 +67,15 @@ doprnt (char *buffer, register int bufsize, const char *format,
62 char tembuf[DBL_MAX_10_EXP + 100]; 67 char tembuf[DBL_MAX_10_EXP + 100];
63 68
64 /* Size of sprintf_buffer. */ 69 /* Size of sprintf_buffer. */
65 unsigned size_allocated = sizeof (tembuf); 70 size_t size_allocated = sizeof (tembuf);
66 71
67 /* Buffer to use for sprintf. Either tembuf or same as BIG_BUFFER. */ 72 /* Buffer to use for sprintf. Either tembuf or same as BIG_BUFFER. */
68 char *sprintf_buffer = tembuf; 73 char *sprintf_buffer = tembuf;
69 74
70 /* Buffer we have got with malloc. */ 75 /* Buffer we have got with malloc. */
71 char *big_buffer = 0; 76 char *big_buffer = NULL;
72 77
73 register int tem; 78 register size_t tem;
74 char *string; 79 char *string;
75 char fixed_buffer[20]; /* Default buffer for small formatting. */ 80 char fixed_buffer[20]; /* Default buffer for small formatting. */
76 char *fmtcpy; 81 char *fmtcpy;
@@ -92,8 +97,9 @@ doprnt (char *buffer, register int bufsize, const char *format,
92 { 97 {
93 if (*fmt == '%') /* Check for a '%' character */ 98 if (*fmt == '%') /* Check for a '%' character */
94 { 99 {
95 unsigned size_bound = 0; 100 size_t size_bound = 0;
96 EMACS_INT width; /* Columns occupied by STRING. */ 101 EMACS_INT width; /* Columns occupied by STRING on display. */
102 int long_flag = 0;
97 103
98 fmt++; 104 fmt++;
99 /* Copy this one %-spec into fmtcpy. */ 105 /* Copy this one %-spec into fmtcpy. */
@@ -108,10 +114,11 @@ doprnt (char *buffer, register int bufsize, const char *format,
108 This might be a field width or a precision; e.g. 114 This might be a field width or a precision; e.g.
109 %1.1000f and %1000.1f both might need 1000+ bytes. 115 %1.1000f and %1000.1f both might need 1000+ bytes.
110 Parse the width or precision, checking for overflow. */ 116 Parse the width or precision, checking for overflow. */
111 unsigned n = *fmt - '0'; 117 size_t n = *fmt - '0';
112 while ('0' <= fmt[1] && fmt[1] <= '9') 118 while ('0' <= fmt[1] && fmt[1] <= '9')
113 { 119 {
114 if (n * 10 + fmt[1] - '0' < n) 120 if (n >= SIZE_MAX / 10
121 || n * 10 > SIZE_MAX - (fmt[1] - '0'))
115 error ("Format width or precision too large"); 122 error ("Format width or precision too large");
116 n = n * 10 + fmt[1] - '0'; 123 n = n * 10 + fmt[1] - '0';
117 *string++ = *++fmt; 124 *string++ = *++fmt;
@@ -122,6 +129,13 @@ doprnt (char *buffer, register int bufsize, const char *format,
122 } 129 }
123 else if (*fmt == '-' || *fmt == ' ' || *fmt == '.' || *fmt == '+') 130 else if (*fmt == '-' || *fmt == ' ' || *fmt == '.' || *fmt == '+')
124 ; 131 ;
132 else if (*fmt == 'l')
133 {
134 long_flag = 1;
135 if (!strchr ("dox", fmt[1]))
136 /* %l as conversion specifier, not as modifier. */
137 break;
138 }
125 else 139 else
126 break; 140 break;
127 fmt++; 141 fmt++;
@@ -130,7 +144,7 @@ doprnt (char *buffer, register int bufsize, const char *format,
130 144
131 /* Make the size bound large enough to handle floating point formats 145 /* Make the size bound large enough to handle floating point formats
132 with large numbers. */ 146 with large numbers. */
133 if (size_bound + DBL_MAX_10_EXP + 50 < size_bound) 147 if (size_bound > SIZE_MAX - DBL_MAX_10_EXP - 50)
134 error ("Format width or precision too large"); 148 error ("Format width or precision too large");
135 size_bound += DBL_MAX_10_EXP + 50; 149 size_bound += DBL_MAX_10_EXP + 50;
136 150
@@ -151,23 +165,47 @@ doprnt (char *buffer, register int bufsize, const char *format,
151 error ("Invalid format operation %%%c", fmt[-1]); 165 error ("Invalid format operation %%%c", fmt[-1]);
152 166
153/* case 'b': */ 167/* case 'b': */
168 case 'l':
154 case 'd': 169 case 'd':
170 {
171 int i;
172 long l;
173
174 if (long_flag)
175 {
176 l = va_arg(ap, long);
177 sprintf (sprintf_buffer, fmtcpy, l);
178 }
179 else
180 {
181 i = va_arg(ap, int);
182 sprintf (sprintf_buffer, fmtcpy, i);
183 }
184 /* Now copy into final output, truncating as necessary. */
185 string = sprintf_buffer;
186 goto doit;
187 }
188
155 case 'o': 189 case 'o':
156 case 'x': 190 case 'x':
157 if (sizeof (int) == sizeof (EMACS_INT)) 191 {
158 ; 192 unsigned u;
159 else if (sizeof (long) == sizeof (EMACS_INT)) 193 unsigned long ul;
160 /* Insert an `l' the right place. */ 194
161 string[1] = string[0], 195 if (long_flag)
162 string[0] = string[-1], 196 {
163 string[-1] = 'l', 197 ul = va_arg(ap, unsigned long);
164 string++; 198 sprintf (sprintf_buffer, fmtcpy, ul);
165 else 199 }
166 abort (); 200 else
167 sprintf (sprintf_buffer, fmtcpy, va_arg(ap, char *)); 201 {
168 /* Now copy into final output, truncating as nec. */ 202 u = va_arg(ap, unsigned);
169 string = sprintf_buffer; 203 sprintf (sprintf_buffer, fmtcpy, u);
170 goto doit; 204 }
205 /* Now copy into final output, truncating as necessary. */
206 string = sprintf_buffer;
207 goto doit;
208 }
171 209
172 case 'f': 210 case 'f':
173 case 'e': 211 case 'e':
@@ -175,7 +213,7 @@ doprnt (char *buffer, register int bufsize, const char *format,
175 { 213 {
176 double d = va_arg(ap, double); 214 double d = va_arg(ap, double);
177 sprintf (sprintf_buffer, fmtcpy, d); 215 sprintf (sprintf_buffer, fmtcpy, d);
178 /* Now copy into final output, truncating as nec. */ 216 /* Now copy into final output, truncating as necessary. */
179 string = sprintf_buffer; 217 string = sprintf_buffer;
180 goto doit; 218 goto doit;
181 } 219 }
@@ -187,13 +225,18 @@ doprnt (char *buffer, register int bufsize, const char *format,
187 minlen = atoi (&fmtcpy[1]); 225 minlen = atoi (&fmtcpy[1]);
188 string = va_arg (ap, char *); 226 string = va_arg (ap, char *);
189 tem = strlen (string); 227 tem = strlen (string);
228 if (tem > MOST_POSITIVE_FIXNUM)
229 error ("String for %%s or %%S format is too long");
190 width = strwidth (string, tem); 230 width = strwidth (string, tem);
191 goto doit1; 231 goto doit1;
192 232
193 /* Copy string into final output, truncating if no room. */ 233 /* Copy string into final output, truncating if no room. */
194 doit: 234 doit:
195 /* Coming here means STRING contains ASCII only. */ 235 /* Coming here means STRING contains ASCII only. */
196 width = tem = strlen (string); 236 tem = strlen (string);
237 if (tem > MOST_POSITIVE_FIXNUM)
238 error ("Format width or precision too large");
239 width = tem;
197 doit1: 240 doit1:
198 /* We have already calculated: 241 /* We have already calculated:
199 TEM -- length of STRING, 242 TEM -- length of STRING,
@@ -236,13 +279,8 @@ doprnt (char *buffer, register int bufsize, const char *format,
236 279
237 case 'c': 280 case 'c':
238 { 281 {
239 /* Sometimes for %c we pass a char, which would widen 282 int chr = va_arg(ap, int);
240 to int. Sometimes we pass XFASTINT() or XINT() 283 tem = CHAR_STRING (chr, (unsigned char *) charbuf);
241 values, which would be EMACS_INT. Let's hope that
242 both are passed the same way, otherwise we'll need
243 to rewrite callers. */
244 EMACS_INT chr = va_arg(ap, EMACS_INT);
245 tem = CHAR_STRING ((int) chr, (unsigned char *) charbuf);
246 string = charbuf; 284 string = charbuf;
247 string[tem] = 0; 285 string[tem] = 0;
248 width = strwidth (string, tem); 286 width = strwidth (string, tem);
@@ -274,6 +312,6 @@ doprnt (char *buffer, register int bufsize, const char *format,
274 /* If we had to malloc something, free it. */ 312 /* If we had to malloc something, free it. */
275 xfree (big_buffer); 313 xfree (big_buffer);
276 314
277 *bufptr = 0; /* Make sure our string end with a '\0' */ 315 *bufptr = 0; /* Make sure our string ends with a '\0' */
278 return bufptr - buffer; 316 return bufptr - buffer;
279} 317}
diff --git a/src/eval.c b/src/eval.c
index b843ca5b2ec..c3676720940 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -1416,7 +1416,8 @@ internal_lisp_condition_case (volatile Lisp_Object var, Lisp_Object bodyform,
1416 || (CONSP (tem) 1416 || (CONSP (tem)
1417 && (SYMBOLP (XCAR (tem)) 1417 && (SYMBOLP (XCAR (tem))
1418 || CONSP (XCAR (tem)))))) 1418 || CONSP (XCAR (tem))))))
1419 error ("Invalid condition handler"); 1419 error ("Invalid condition handler: %s",
1420 SDATA (Fprin1_to_string (tem, Qt)));
1420 } 1421 }
1421 1422
1422 c.tag = Qnil; 1423 c.tag = Qnil;
@@ -1995,31 +1996,31 @@ verror (const char *m, va_list ap)
1995 size_t size = sizeof buf; 1996 size_t size = sizeof buf;
1996 size_t size_max = 1997 size_t size_max =
1997 min (MOST_POSITIVE_FIXNUM, min (INT_MAX, SIZE_MAX - 1)) + 1; 1998 min (MOST_POSITIVE_FIXNUM, min (INT_MAX, SIZE_MAX - 1)) + 1;
1999 size_t mlen = strlen (m);
1998 char *buffer = buf; 2000 char *buffer = buf;
1999 int used; 2001 size_t used;
2000 Lisp_Object string; 2002 Lisp_Object string;
2001 2003
2002 while (1) 2004 while (1)
2003 { 2005 {
2004 used = vsnprintf (buffer, size, m, ap); 2006 used = doprnt (buffer, size, m, m + mlen, ap);
2005 2007
2006 if (used < 0) 2008 /* Note: the -1 below is because `doprnt' returns the number of bytes
2007 { 2009 excluding the terminating null byte, and it always terminates with a
2008 /* Non-C99 vsnprintf, such as w32, returns -1 when SIZE is too small. 2010 null byte, even when producing a truncated message. */
2009 Guess a larger USED to work around the incompatibility. */ 2011 if (used < size - 1)
2010 used = (size <= size_max / 2 ? 2 * size
2011 : size < size_max ? size_max - 1
2012 : size_max);
2013 }
2014 else if (used < size)
2015 break; 2012 break;
2016 if (size_max <= used) 2013 if (size <= size_max / 2)
2017 memory_full (); 2014 size *= 2;
2018 size = used + 1; 2015 else if (size < size_max - 1)
2016 size = size_max - 1;
2017 else
2018 break; /* and leave the message truncated */
2019 2019
2020 if (buffer != buf) 2020 if (buffer == buf)
2021 xfree (buffer); 2021 buffer = (char *) xmalloc (size);
2022 buffer = (char *) xmalloc (size); 2022 else
2023 buffer = (char *) xrealloc (buffer, size);
2023 } 2024 }
2024 2025
2025 string = make_string (buffer, used); 2026 string = make_string (buffer, used);
diff --git a/src/font.c b/src/font.c
index 7fe0815d80e..f4950d39189 100644
--- a/src/font.c
+++ b/src/font.c
@@ -1795,14 +1795,16 @@ check_otf_features (otf_features)
1795 { 1795 {
1796 CHECK_SYMBOL (Fcar (val)); 1796 CHECK_SYMBOL (Fcar (val));
1797 if (SBYTES (SYMBOL_NAME (XCAR (val))) > 4) 1797 if (SBYTES (SYMBOL_NAME (XCAR (val))) > 4)
1798 error ("Invalid OTF GSUB feature: %s", SYMBOL_NAME (XCAR (val))); 1798 error ("Invalid OTF GSUB feature: %s",
1799 SDATA (SYMBOL_NAME (XCAR (val))));
1799 } 1800 }
1800 otf_features = XCDR (otf_features); 1801 otf_features = XCDR (otf_features);
1801 for (val = Fcar (otf_features); ! NILP (val); val = Fcdr (val)) 1802 for (val = Fcar (otf_features); ! NILP (val); val = Fcdr (val))
1802 { 1803 {
1803 CHECK_SYMBOL (Fcar (val)); 1804 CHECK_SYMBOL (Fcar (val));
1804 if (SBYTES (SYMBOL_NAME (XCAR (val))) > 4) 1805 if (SBYTES (SYMBOL_NAME (XCAR (val))) > 4)
1805 error ("Invalid OTF GPOS feature: %s", SYMBOL_NAME (XCAR (val))); 1806 error ("Invalid OTF GPOS feature: %s",
1807 SDATA (SYMBOL_NAME (XCAR (val))));
1806 } 1808 }
1807} 1809}
1808 1810
diff --git a/src/lisp.h b/src/lisp.h
index 581835dd32b..07b2cb0b1ef 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -2760,6 +2760,9 @@ extern Lisp_Object internal_with_output_to_temp_buffer
2760extern void float_to_string (char *, double); 2760extern void float_to_string (char *, double);
2761extern void syms_of_print (void); 2761extern void syms_of_print (void);
2762 2762
2763/* Defined in doprnt.c */
2764extern size_t doprnt (char *, size_t, const char *, const char *, va_list);
2765
2763/* Defined in lread.c. */ 2766/* Defined in lread.c. */
2764extern Lisp_Object Qvariable_documentation, Qstandard_input; 2767extern Lisp_Object Qvariable_documentation, Qstandard_input;
2765extern Lisp_Object Qbackquote, Qcomma, Qcomma_at, Qcomma_dot, Qfunction; 2768extern Lisp_Object Qbackquote, Qcomma, Qcomma_at, Qcomma_dot, Qfunction;
diff --git a/src/makefile.w32-in b/src/makefile.w32-in
index 62c40ca1f94..9d2c3d8f83f 100644
--- a/src/makefile.w32-in
+++ b/src/makefile.w32-in
@@ -469,6 +469,7 @@ $(BLD)/callint.$(O) : \
469 $(EMACS_ROOT)/nt/inc/sys/time.h \ 469 $(EMACS_ROOT)/nt/inc/sys/time.h \
470 $(LISP_H) \ 470 $(LISP_H) \
471 $(SRC)/buffer.h \ 471 $(SRC)/buffer.h \
472 $(SRC)/character.h \
472 $(SRC)/coding.h \ 473 $(SRC)/coding.h \
473 $(SRC)/commands.h \ 474 $(SRC)/commands.h \
474 $(SRC)/composite.h \ 475 $(SRC)/composite.h \
diff --git a/src/xdisp.c b/src/xdisp.c
index 19fef35fce8..91d1b6ea2e3 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -8373,22 +8373,10 @@ vmessage (const char *m, va_list ap)
8373 { 8373 {
8374 if (m) 8374 if (m)
8375 { 8375 {
8376 char *buf = FRAME_MESSAGE_BUF (f); 8376 size_t len;
8377 size_t bufsize = FRAME_MESSAGE_BUF_SIZE (f);
8378 int len;
8379 8377
8380 memset (buf, 0, bufsize); 8378 len = doprnt (FRAME_MESSAGE_BUF (f),
8381 len = vsnprintf (buf, bufsize, m, ap); 8379 FRAME_MESSAGE_BUF_SIZE (f), m, (char *)0, ap);
8382
8383 /* Do any truncation at a character boundary. */
8384 if (! (0 <= len && len < bufsize))
8385 {
8386 char *end = memchr (buf, 0, bufsize);
8387 for (len = end ? end - buf : bufsize;
8388 len && ! CHAR_HEAD_P (buf[len - 1]);
8389 len--)
8390 continue;
8391 }
8392 8380
8393 message2 (FRAME_MESSAGE_BUF (f), len, 0); 8381 message2 (FRAME_MESSAGE_BUF (f), len, 0);
8394 } 8382 }