Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit b69a27e

Browse files
committed
code part of patch #100895 by Fredrik Lundh
PyErr_Format computes size of buffer needed rather than relying on static buffer.
1 parent 51ee09b commit b69a27e

1 file changed

Lines changed: 124 additions & 4 deletions

File tree

Python/errors.c

Lines changed: 124 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ extern char *strerror(int);
2929
#include "winbase.h"
3030
#endif
3131

32+
#include <ctype.h>
33+
3234
void
3335
PyErr_Restore(PyObject *type, PyObject *value, PyObject *traceback)
3436
{
@@ -364,7 +366,6 @@ PyObject *PyErr_SetFromWindowsErrWithFilename(
364366
PyObject *PyErr_SetFromWindowsErr(int ierr)
365367
{
366368
return PyErr_SetFromWindowsErrWithFilename(ierr, NULL);
367-
368369
}
369370
#endif /* MS_WINDOWS */
370371

@@ -393,12 +394,131 @@ PyObject *
393394
PyErr_Format(PyObject *exception, const char *format, ...)
394395
{
395396
va_list vargs;
396-
char buffer[500]; /* Caller is responsible for limiting the format */
397+
int n, i;
398+
const char* f;
399+
char* s;
400+
PyObject* string;
397401

402+
/* step 1: figure out how large a buffer we need */
403+
404+
#ifdef HAVE_STDARG_PROTOTYPES
398405
va_start(vargs, format);
406+
#else
407+
va_start(vargs);
408+
#endif
399409

400-
vsprintf(buffer, format, vargs);
401-
PyErr_SetString(exception, buffer);
410+
n = 0;
411+
for (f = format; *f; f++) {
412+
if (*f == '%') {
413+
const char* p = f;
414+
while (*++f && *f != '%' && !isalpha(*f))
415+
;
416+
switch (*f) {
417+
case 'c':
418+
va_arg(vargs, int);
419+
/* fall through... */
420+
case '%':
421+
n++;
422+
break;
423+
case 'd': case 'i': case 'x':
424+
va_arg(vargs, int);
425+
/* 20 bytes should be enough to hold a 64-bit
426+
integer */
427+
n = n + 20;
428+
break;
429+
case 's':
430+
s = va_arg(vargs, char*);
431+
n = n + strlen(s);
432+
break;
433+
default:
434+
/* if we stumble upon an unknown
435+
formatting code, copy the rest of
436+
the format string to the output
437+
string. (we cannot just skip the
438+
code, since there's no way to know
439+
what's in the argument list) */
440+
n = n + strlen(p);
441+
goto expand;
442+
}
443+
} else
444+
n = n + 1;
445+
}
446+
447+
expand:
448+
449+
string = PyString_FromStringAndSize(NULL, n);
450+
if (!string)
451+
return NULL;
452+
453+
#ifdef HAVE_STDARG_PROTOTYPES
454+
va_start(vargs, format);
455+
#else
456+
va_start(vargs);
457+
#endif
458+
459+
/* step 2: fill the buffer */
460+
461+
s = PyString_AsString(string);
462+
463+
for (f = format; *f; f++) {
464+
if (*f == '%') {
465+
const char* p = f++;
466+
/* parse the width.precision part (we're only
467+
interested in the precision value, if any) */
468+
n = 0;
469+
while (isdigit(*f))
470+
n = (n*10) + *f++ - '0';
471+
if (*f == '.') {
472+
f++;
473+
n = 0;
474+
while (isdigit(*f))
475+
n = (n*10) + *f++ - '0';
476+
}
477+
while (*f && *f != '%' && !isalpha(*f))
478+
f++;
479+
switch (*f) {
480+
case 'c':
481+
*s++ = va_arg(vargs, int);
482+
break;
483+
case 'd':
484+
sprintf(s, "%d", va_arg(vargs, int));
485+
s = s + strlen(s);
486+
break;
487+
case 'i':
488+
sprintf(s, "%i", va_arg(vargs, int));
489+
s = s + strlen(s);
490+
break;
491+
case 'x':
492+
sprintf(s, "%x", va_arg(vargs, int));
493+
s = s + strlen(s);
494+
break;
495+
case 's':
496+
p = va_arg(vargs, char*);
497+
i = strlen(p);
498+
if (n > 0 && i > n)
499+
i = n;
500+
memcpy(s, p, i);
501+
s = s + i;
502+
break;
503+
case '%':
504+
*s++ = '%';
505+
break;
506+
default:
507+
strcpy(s, p);
508+
s = s + strlen(s);
509+
goto end;
510+
}
511+
} else
512+
*s++ = *f;
513+
}
514+
515+
end:
516+
517+
_PyString_Resize(&string, s - PyString_AsString(string));
518+
519+
PyErr_SetObject(exception, string);
520+
Py_XDECREF(string);
521+
402522
return NULL;
403523
}
404524

0 commit comments

Comments
 (0)