aboutsummaryrefslogtreecommitdiffstats
path: root/lib/vsprintf.c
diff options
context:
space:
mode:
authorJeremy Fitzhardinge <jeremy@xensource.com>2006-06-25 08:49:17 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-06-25 13:01:23 -0400
commitf796937a062c7aeb44cd0e75e1586c8543634a7d (patch)
treec3cfcbb27e291621e31cff71288f3e82d8b149a8 /lib/vsprintf.c
parent891c668b90ded38cec36f0852c4983573597170d (diff)
[PATCH] Fix bounds check in vsnprintf, to allow for a 0 size and NULL buffer
This change allows callers to use a 0-byte buffer and a NULL buffer pointer with vsnprintf, so it can be used to determine how large the resulting formatted string will be. Previously the code effectively treated a size of 0 as a size of 4G (on 32-bit systems), with other checks preventing it from actually trying to emit the string - but the terminal \0 would still be written, which would crash if the buffer is NULL. This change changes the boundary check so that 'end' points to the putative location of the terminal '\0', which is only written if size > 0. vsnprintf still allows the buffer size to be set very large, to allow unbounded buffer sizes (to implement sprintf, etc). [akpm@osdl.org: fix long-vs-longlong confusion] Signed-off-by: Jeremy Fitzhardinge <jeremy@xensource.com> Signed-off-by: Chris Wright <chrisw@sous-sol.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'lib/vsprintf.c')
-rw-r--r--lib/vsprintf.c65
1 files changed, 33 insertions, 32 deletions
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index b07db5ca3f66..f5959476e53d 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -187,49 +187,49 @@ static char * number(char * buf, char * end, unsigned long long num, int base, i
187 size -= precision; 187 size -= precision;
188 if (!(type&(ZEROPAD+LEFT))) { 188 if (!(type&(ZEROPAD+LEFT))) {
189 while(size-->0) { 189 while(size-->0) {
190 if (buf <= end) 190 if (buf < end)
191 *buf = ' '; 191 *buf = ' ';
192 ++buf; 192 ++buf;
193 } 193 }
194 } 194 }
195 if (sign) { 195 if (sign) {
196 if (buf <= end) 196 if (buf < end)
197 *buf = sign; 197 *buf = sign;
198 ++buf; 198 ++buf;
199 } 199 }
200 if (type & SPECIAL) { 200 if (type & SPECIAL) {
201 if (base==8) { 201 if (base==8) {
202 if (buf <= end) 202 if (buf < end)
203 *buf = '0'; 203 *buf = '0';
204 ++buf; 204 ++buf;
205 } else if (base==16) { 205 } else if (base==16) {
206 if (buf <= end) 206 if (buf < end)
207 *buf = '0'; 207 *buf = '0';
208 ++buf; 208 ++buf;
209 if (buf <= end) 209 if (buf < end)
210 *buf = digits[33]; 210 *buf = digits[33];
211 ++buf; 211 ++buf;
212 } 212 }
213 } 213 }
214 if (!(type & LEFT)) { 214 if (!(type & LEFT)) {
215 while (size-- > 0) { 215 while (size-- > 0) {
216 if (buf <= end) 216 if (buf < end)
217 *buf = c; 217 *buf = c;
218 ++buf; 218 ++buf;
219 } 219 }
220 } 220 }
221 while (i < precision--) { 221 while (i < precision--) {
222 if (buf <= end) 222 if (buf < end)
223 *buf = '0'; 223 *buf = '0';
224 ++buf; 224 ++buf;
225 } 225 }
226 while (i-- > 0) { 226 while (i-- > 0) {
227 if (buf <= end) 227 if (buf < end)
228 *buf = tmp[i]; 228 *buf = tmp[i];
229 ++buf; 229 ++buf;
230 } 230 }
231 while (size-- > 0) { 231 while (size-- > 0) {
232 if (buf <= end) 232 if (buf < end)
233 *buf = ' '; 233 *buf = ' ';
234 ++buf; 234 ++buf;
235 } 235 }
@@ -272,7 +272,8 @@ int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
272 /* 'z' changed to 'Z' --davidm 1/25/99 */ 272 /* 'z' changed to 'Z' --davidm 1/25/99 */
273 /* 't' added for ptrdiff_t */ 273 /* 't' added for ptrdiff_t */
274 274
275 /* Reject out-of-range values early */ 275 /* Reject out-of-range values early. Large positive sizes are
276 used for unknown buffer sizes. */
276 if (unlikely((int) size < 0)) { 277 if (unlikely((int) size < 0)) {
277 /* There can be only one.. */ 278 /* There can be only one.. */
278 static int warn = 1; 279 static int warn = 1;
@@ -282,16 +283,17 @@ int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
282 } 283 }
283 284
284 str = buf; 285 str = buf;
285 end = buf + size - 1; 286 end = buf + size;
286 287
287 if (end < buf - 1) { 288 /* Make sure end is always >= buf */
288 end = ((void *) -1); 289 if (end < buf) {
289 size = end - buf + 1; 290 end = ((void *)-1);
291 size = end - buf;
290 } 292 }
291 293
292 for (; *fmt ; ++fmt) { 294 for (; *fmt ; ++fmt) {
293 if (*fmt != '%') { 295 if (*fmt != '%') {
294 if (str <= end) 296 if (str < end)
295 *str = *fmt; 297 *str = *fmt;
296 ++str; 298 ++str;
297 continue; 299 continue;
@@ -357,17 +359,17 @@ int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
357 case 'c': 359 case 'c':
358 if (!(flags & LEFT)) { 360 if (!(flags & LEFT)) {
359 while (--field_width > 0) { 361 while (--field_width > 0) {
360 if (str <= end) 362 if (str < end)
361 *str = ' '; 363 *str = ' ';
362 ++str; 364 ++str;
363 } 365 }
364 } 366 }
365 c = (unsigned char) va_arg(args, int); 367 c = (unsigned char) va_arg(args, int);
366 if (str <= end) 368 if (str < end)
367 *str = c; 369 *str = c;
368 ++str; 370 ++str;
369 while (--field_width > 0) { 371 while (--field_width > 0) {
370 if (str <= end) 372 if (str < end)
371 *str = ' '; 373 *str = ' ';
372 ++str; 374 ++str;
373 } 375 }
@@ -382,18 +384,18 @@ int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
382 384
383 if (!(flags & LEFT)) { 385 if (!(flags & LEFT)) {
384 while (len < field_width--) { 386 while (len < field_width--) {
385 if (str <= end) 387 if (str < end)
386 *str = ' '; 388 *str = ' ';
387 ++str; 389 ++str;
388 } 390 }
389 } 391 }
390 for (i = 0; i < len; ++i) { 392 for (i = 0; i < len; ++i) {
391 if (str <= end) 393 if (str < end)
392 *str = *s; 394 *str = *s;
393 ++str; ++s; 395 ++str; ++s;
394 } 396 }
395 while (len < field_width--) { 397 while (len < field_width--) {
396 if (str <= end) 398 if (str < end)
397 *str = ' '; 399 *str = ' ';
398 ++str; 400 ++str;
399 } 401 }
@@ -426,7 +428,7 @@ int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
426 continue; 428 continue;
427 429
428 case '%': 430 case '%':
429 if (str <= end) 431 if (str < end)
430 *str = '%'; 432 *str = '%';
431 ++str; 433 ++str;
432 continue; 434 continue;
@@ -449,11 +451,11 @@ int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
449 break; 451 break;
450 452
451 default: 453 default:
452 if (str <= end) 454 if (str < end)
453 *str = '%'; 455 *str = '%';
454 ++str; 456 ++str;
455 if (*fmt) { 457 if (*fmt) {
456 if (str <= end) 458 if (str < end)
457 *str = *fmt; 459 *str = *fmt;
458 ++str; 460 ++str;
459 } else { 461 } else {
@@ -483,14 +485,13 @@ int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
483 str = number(str, end, num, base, 485 str = number(str, end, num, base,
484 field_width, precision, flags); 486 field_width, precision, flags);
485 } 487 }
486 if (str <= end) 488 if (size > 0) {
487 *str = '\0'; 489 if (str < end)
488 else if (size > 0) 490 *str = '\0';
489 /* don't write out a null byte if the buf size is zero */ 491 else
490 *end = '\0'; 492 *end = '\0';
491 /* the trailing null byte doesn't count towards the total 493 }
492 * ++str; 494 /* the trailing null byte doesn't count towards the total */
493 */
494 return str-buf; 495 return str-buf;
495} 496}
496 497