diff options
Diffstat (limited to 'src/doprnt.c')
| -rw-r--r-- | src/doprnt.c | 106 |
1 files changed, 72 insertions, 34 deletions
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 | ||
| 54 | EMACS_INT | 59 | size_t |
| 55 | doprnt (char *buffer, register int bufsize, const char *format, | 60 | doprnt (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 | } |