diff options
author | Martin Wilke <miwi@FreeBSD.org> | 2008-09-11 08:05:23 +0000 |
---|---|---|
committer | Martin Wilke <miwi@FreeBSD.org> | 2008-09-11 08:05:23 +0000 |
commit | 5d6556dc39098800e88d6345d23bd810c72d0b39 (patch) | |
tree | e561cacf743e1c5aab98ca14014ecdcbdc988693 /lang | |
parent | - Document python -- multiple vulnerabilities (diff) |
- add patches from upstream svn rev.65333, fix integer overflows in
memory allocation (CVE-2008-2315 and CVE-2008-2316)
- also apply upstream svn rev.65262, fixes overflow checks in memory
allocation (CVE-2008-3142 and CVE-2008-3144)
Approved by: portmgr (pav)
Security: http://www.vuxml.org/freebsd/0dccaa28-7f3c-11dd-8de5-0030843d3802.html
Notes
Notes:
svn path=/head/; revision=220331
Diffstat (limited to 'lang')
-rw-r--r-- | lang/python24/Makefile | 2 | ||||
-rw-r--r-- | lang/python24/files/patch-include-pymem.h | 58 | ||||
-rw-r--r-- | lang/python24/files/patch-module_arraymodule.c | 33 | ||||
-rw-r--r-- | lang/python24/files/patch-module_obmalloc.c | 34 | ||||
-rw-r--r-- | lang/python24/files/patch-module_selectmodule.c | 16 | ||||
-rw-r--r-- | lang/python24/files/patch-modules_almodule.c | 14 | ||||
-rw-r--r-- | lang/python24/files/patch-modules_gcmodule.c | 23 | ||||
-rw-r--r-- | lang/python24/files/patch-modules_mmapmodule.c | 11 | ||||
-rw-r--r-- | lang/python24/files/patch-modules_stropmodule.c | 31 | ||||
-rw-r--r-- | lang/python24/files/patch-objects-bufferobject.c | 13 | ||||
-rw-r--r-- | lang/python24/files/patch-objects_stringobject.c | 42 | ||||
-rw-r--r-- | lang/python24/files/patch-objects_tupleobject.c | 17 | ||||
-rw-r--r-- | lang/python24/files/patch-objects_unicodeobject.c | 112 | ||||
-rw-r--r-- | lang/python24/files/patch-python_mysnprintf.c | 55 |
14 files changed, 460 insertions, 1 deletions
diff --git a/lang/python24/Makefile b/lang/python24/Makefile index 3e719978b300..ca99497844b4 100644 --- a/lang/python24/Makefile +++ b/lang/python24/Makefile @@ -7,7 +7,7 @@ PORTNAME= python24 PORTVERSION= 2.4.5 -PORTREVISION= 1 +PORTREVISION= 2 CATEGORIES= lang python ipv6 MASTER_SITES= ${PYTHON_MASTER_SITES} MASTER_SITE_SUBDIR= ${PYTHON_MASTER_SITE_SUBDIR} diff --git a/lang/python24/files/patch-include-pymem.h b/lang/python24/files/patch-include-pymem.h new file mode 100644 index 000000000000..cafb6ae52698 --- /dev/null +++ b/lang/python24/files/patch-include-pymem.h @@ -0,0 +1,58 @@ +--- Include/pymem.h.orig 2008-03-02 20:20:32.000000000 +0100 ++++ Include/pymem.h +@@ -66,8 +66,12 @@ PyAPI_FUNC(void) PyMem_Free(void *); + for malloc(0), which would be treated as an error. Some platforms + would return a pointer with no memory behind it, which would break + pymalloc. To solve these problems, allocate an extra byte. */ +-#define PyMem_MALLOC(n) malloc((n) ? (n) : 1) +-#define PyMem_REALLOC(p, n) realloc((p), (n) ? (n) : 1) ++/* Returns NULL to indicate error if a negative size or size larger than ++ Py_ssize_t can represent is supplied. Helps prevents security holes. */ ++#define PyMem_MALLOC(n) (((n) < 0 || (n) > INT_MAX) ? NULL \ ++ : malloc((n) ? (n) : 1)) ++#define PyMem_REALLOC(p, n) (((n) < 0 || (n) > INT_MAX) ? NULL \ ++ : realloc((p), (n) ? (n) : 1)) + + #endif /* PYMALLOC_DEBUG */ + +@@ -80,24 +84,31 @@ PyAPI_FUNC(void) PyMem_Free(void *); + * Type-oriented memory interface + * ============================== + * +- * These are carried along for historical reasons. There's rarely a good +- * reason to use them anymore (you can just as easily do the multiply and +- * cast yourself). ++ * Allocate memory for n objects of the given type. Returns a new pointer ++ * or NULL if the request was too large or memory allocation failed. Use ++ * these macros rather than doing the multiplication yourself so that proper ++ * overflow checking is always done. + */ + + #define PyMem_New(type, n) \ +- ( assert((n) <= PY_SIZE_MAX / sizeof(type)) , \ ++ ( ((n) > INT_MAX / sizeof(type)) ? NULL : \ + ( (type *) PyMem_Malloc((n) * sizeof(type)) ) ) + #define PyMem_NEW(type, n) \ +- ( assert((n) <= PY_SIZE_MAX / sizeof(type)) , \ ++ ( ((n) > INT_MAX / sizeof(type)) ? NULL : \ + ( (type *) PyMem_MALLOC((n) * sizeof(type)) ) ) + ++/* ++ * The value of (p) is always clobbered by this macro regardless of success. ++ * The caller MUST check if (p) is NULL afterwards and deal with the memory ++ * error if so. This means the original value of (p) MUST be saved for the ++ * caller's memory error handler to not lose track of it. ++ */ + #define PyMem_Resize(p, type, n) \ +- ( assert((n) <= PY_SIZE_MAX / sizeof(type)) , \ +- ( (p) = (type *) PyMem_Realloc((p), (n) * sizeof(type)) ) ) ++ ( (p) = ((n) > INT_MAX / sizeof(type)) ? NULL : \ ++ (type *) PyMem_Realloc((p), (n) * sizeof(type)) ) + #define PyMem_RESIZE(p, type, n) \ +- ( assert((n) <= PY_SIZE_MAX / sizeof(type)) , \ +- ( (p) = (type *) PyMem_REALLOC((p), (n) * sizeof(type)) ) ) ++ ( (p) = ((n) > INT_MAX / sizeof(type)) ? NULL : \ ++ (type *) PyMem_REALLOC((p), (n) * sizeof(type)) ) + + /* In order to avoid breaking old code mixing PyObject_{New, NEW} with + PyMem_{Del, DEL} and PyMem_{Free, FREE}, the PyMem "release memory" diff --git a/lang/python24/files/patch-module_arraymodule.c b/lang/python24/files/patch-module_arraymodule.c new file mode 100644 index 000000000000..6dcfb467f619 --- /dev/null +++ b/lang/python24/files/patch-module_arraymodule.c @@ -0,0 +1,33 @@ +--- Modules/arraymodule.c.orig 2008-03-02 20:20:32.000000000 +0100 ++++ Modules/arraymodule.c +@@ -814,6 +814,7 @@ static int + array_do_extend(arrayobject *self, PyObject *bb) + { + int size; ++ char *old_item; + + if (!array_Check(bb)) + return array_iter_extend(self, bb); +@@ -829,10 +830,11 @@ array_do_extend(arrayobject *self, PyObj + return -1; + } + size = self->ob_size + b->ob_size; ++ old_item = self->ob_item; + PyMem_RESIZE(self->ob_item, char, size*self->ob_descr->itemsize); + if (self->ob_item == NULL) { +- PyObject_Del(self); +- PyErr_NoMemory(); ++ self->ob_item = old_item; ++ PyErr_NoMemory(); + return -1; + } + memcpy(self->ob_item + self->ob_size*self->ob_descr->itemsize, +@@ -884,7 +886,7 @@ array_inplace_repeat(arrayobject *self, + if (size > INT_MAX / n) { + return PyErr_NoMemory(); + } +- PyMem_Resize(items, char, n * size); ++ PyMem_RESIZE(items, char, n * size); + if (items == NULL) + return PyErr_NoMemory(); + p = items; diff --git a/lang/python24/files/patch-module_obmalloc.c b/lang/python24/files/patch-module_obmalloc.c new file mode 100644 index 000000000000..9373b40be181 --- /dev/null +++ b/lang/python24/files/patch-module_obmalloc.c @@ -0,0 +1,34 @@ +--- Objects/obmalloc.c.orig 2005-07-11 07:57:11.000000000 +0200 ++++ Objects/obmalloc.c +@@ -585,6 +585,15 @@ PyObject_Malloc(size_t nbytes) + uint size; + + /* ++ * Limit ourselves to INT_MAX bytes to prevent security holes. ++ * Most python internals blindly use a signed Py_ssize_t to track ++ * things without checking for overflows or negatives. ++ * As size_t is unsigned, checking for nbytes < 0 is not required. ++ */ ++ if (nbytes > INT_MAX) ++ return NULL; ++ ++ /* + * This implicitly redirects malloc(0). + */ + if ((nbytes - 1) < SMALL_REQUEST_THRESHOLD) { +@@ -814,6 +823,15 @@ PyObject_Realloc(void *p, size_t nbytes) + if (p == NULL) + return PyObject_Malloc(nbytes); + ++ /* ++ * Limit ourselves to INT_MAX bytes to prevent security holes. ++ * Most python internals blindly use a signed Py_ssize_t to track ++ * things without checking for overflows or negatives. ++ * As size_t is unsigned, checking for nbytes < 0 is not required. ++ */ ++ if (nbytes > INT_MAX) ++ return NULL; ++ + pool = POOL_ADDR(p); + if (Py_ADDRESS_IN_RANGE(p, pool)) { + /* We're in charge of this block */ diff --git a/lang/python24/files/patch-module_selectmodule.c b/lang/python24/files/patch-module_selectmodule.c new file mode 100644 index 000000000000..bbcaab9b040d --- /dev/null +++ b/lang/python24/files/patch-module_selectmodule.c @@ -0,0 +1,16 @@ +--- Modules/selectmodule.c.orig 2006-09-27 21:17:32.000000000 +0200 ++++ Modules/selectmodule.c +@@ -342,10 +342,12 @@ update_ufd_array(pollObject *self) + { + int i, pos; + PyObject *key, *value; ++ struct pollfd *old_ufds = self->ufds; + + self->ufd_len = PyDict_Size(self->dict); +- PyMem_Resize(self->ufds, struct pollfd, self->ufd_len); ++ PyMem_RESIZE(self->ufds, struct pollfd, self->ufd_len); + if (self->ufds == NULL) { ++ self->ufds = old_ufds; + PyErr_NoMemory(); + return 0; + } diff --git a/lang/python24/files/patch-modules_almodule.c b/lang/python24/files/patch-modules_almodule.c new file mode 100644 index 000000000000..dbd031e28b8f --- /dev/null +++ b/lang/python24/files/patch-modules_almodule.c @@ -0,0 +1,14 @@ +--- Modules/almodule.c.orig 2006-09-27 21:17:32.000000000 +0200 ++++ Modules/almodule.c +@@ -1633,9 +1633,11 @@ al_QueryValues(PyObject *self, PyObject + if (nvals < 0) + goto cleanup; + if (nvals > setsize) { ++ ALvalue *old_return_set = return_set; + setsize = nvals; + PyMem_RESIZE(return_set, ALvalue, setsize); + if (return_set == NULL) { ++ return_set = old_return_set; + PyErr_NoMemory(); + goto cleanup; + } diff --git a/lang/python24/files/patch-modules_gcmodule.c b/lang/python24/files/patch-modules_gcmodule.c new file mode 100644 index 000000000000..6f16ac7ee2e0 --- /dev/null +++ b/lang/python24/files/patch-modules_gcmodule.c @@ -0,0 +1,23 @@ +--- Modules/gcmodule.c.orig 2006-09-28 19:08:01.000000000 +0200 ++++ Modules/gcmodule.c +@@ -1249,7 +1249,10 @@ PyObject * + _PyObject_GC_Malloc(size_t basicsize) + { + PyObject *op; +- PyGC_Head *g = PyObject_MALLOC(sizeof(PyGC_Head) + basicsize); ++ PyGC_Head *g; ++ if (basicsize > INT_MAX - sizeof(PyGC_Head)) ++ return PyErr_NoMemory(); ++ g = PyObject_MALLOC(sizeof(PyGC_Head) + basicsize); + if (g == NULL) + return PyErr_NoMemory(); + g->gc.gc_refs = GC_UNTRACKED; +@@ -1291,6 +1294,8 @@ _PyObject_GC_Resize(PyVarObject *op, int + { + const size_t basicsize = _PyObject_VAR_SIZE(op->ob_type, nitems); + PyGC_Head *g = AS_GC(op); ++ if (basicsize > INT_MAX - sizeof(PyGC_Head)) ++ return (PyVarObject *)PyErr_NoMemory(); + g = PyObject_REALLOC(g, sizeof(PyGC_Head) + basicsize); + if (g == NULL) + return (PyVarObject *)PyErr_NoMemory(); diff --git a/lang/python24/files/patch-modules_mmapmodule.c b/lang/python24/files/patch-modules_mmapmodule.c new file mode 100644 index 000000000000..0c2f7d761971 --- /dev/null +++ b/lang/python24/files/patch-modules_mmapmodule.c @@ -0,0 +1,11 @@ +--- Modules/mmapmodule.c.orig 2008-08-05 12:00:52.000000000 +0200 ++++ Modules/mmapmodule.c +@@ -223,7 +223,7 @@ mmap_read_method(mmap_object *self, + return(NULL); + + /* silently 'adjust' out-of-range requests */ +- if ((self->pos + num_bytes) > self->size) { ++ if (num_bytes > self->size - self->pos) { + num_bytes -= (self->pos+num_bytes) - self->size; + } + result = Py_BuildValue("s#", self->data+self->pos, num_bytes); diff --git a/lang/python24/files/patch-modules_stropmodule.c b/lang/python24/files/patch-modules_stropmodule.c new file mode 100644 index 000000000000..13e0c837b3c6 --- /dev/null +++ b/lang/python24/files/patch-modules_stropmodule.c @@ -0,0 +1,31 @@ +--- Modules/stropmodule.c.orig 2008-03-02 20:20:32.000000000 +0100 ++++ Modules/stropmodule.c +@@ -214,6 +214,13 @@ strop_joinfields(PyObject *self, PyObjec + return NULL; + } + slen = PyString_GET_SIZE(item); ++ if (slen > INT_MAX - reslen || ++ seplen > INT_MAX - reslen - seplen) { ++ PyErr_SetString(PyExc_OverflowError, ++ "input too long"); ++ Py_DECREF(res); ++ return NULL; ++ } + while (reslen + slen + seplen >= sz) { + if (_PyString_Resize(&res, sz * 2) < 0) + return NULL; +@@ -251,6 +258,14 @@ strop_joinfields(PyObject *self, PyObjec + return NULL; + } + slen = PyString_GET_SIZE(item); ++ if (slen > INT_MAX - reslen || ++ seplen > INT_MAX - reslen - seplen) { ++ PyErr_SetString(PyExc_OverflowError, ++ "input too long"); ++ Py_DECREF(res); ++ Py_XDECREF(item); ++ return NULL; ++ } + while (reslen + slen + seplen >= sz) { + if (_PyString_Resize(&res, sz * 2) < 0) { + Py_DECREF(item); diff --git a/lang/python24/files/patch-objects-bufferobject.c b/lang/python24/files/patch-objects-bufferobject.c new file mode 100644 index 000000000000..6d750015d846 --- /dev/null +++ b/lang/python24/files/patch-objects-bufferobject.c @@ -0,0 +1,13 @@ +--- Objects/bufferobject.c.orig 2008-03-02 20:20:32.000000000 +0100 ++++ Objects/bufferobject.c +@@ -384,6 +384,10 @@ buffer_repeat(PyBufferObject *self, int + count = 0; + if (!get_buf(self, &ptr, &size)) + return NULL; ++ if (count > INT_MAX / size) { ++ PyErr_SetString(PyExc_MemoryError, "result too large"); ++ return NULL; ++ } + ob = PyString_FromStringAndSize(NULL, size * count); + if ( ob == NULL ) + return NULL; diff --git a/lang/python24/files/patch-objects_stringobject.c b/lang/python24/files/patch-objects_stringobject.c new file mode 100644 index 000000000000..0dd33f7a5cc0 --- /dev/null +++ b/lang/python24/files/patch-objects_stringobject.c @@ -0,0 +1,42 @@ +--- Objects/stringobject.c.orig 2006-10-06 21:26:14.000000000 +0200 ++++ Objects/stringobject.c +@@ -69,6 +69,11 @@ PyString_FromStringAndSize(const char *s + return (PyObject *)op; + } + ++ if (size > INT_MAX - sizeof(PyStringObject)) { ++ PyErr_SetString(PyExc_OverflowError, "string is too large"); ++ return NULL; ++ } ++ + /* Inline PyObject_NewVar */ + op = (PyStringObject *)PyObject_MALLOC(sizeof(PyStringObject) + size); + if (op == NULL) +@@ -104,7 +109,7 @@ PyString_FromString(const char *str) + + assert(str != NULL); + size = strlen(str); +- if (size > INT_MAX) { ++ if (size > INT_MAX - sizeof(PyStringObject)) { + PyErr_SetString(PyExc_OverflowError, + "string is too long for a Python string"); + return NULL; +@@ -907,7 +912,18 @@ string_concat(register PyStringObject *a + Py_INCREF(a); + return (PyObject *)a; + } ++ /* Check that string sizes are not negative, to prevent an ++ overflow in cases where we are passed incorrectly-created ++ strings with negative lengths (due to a bug in other code). ++ */ + size = a->ob_size + b->ob_size; ++ if (a->ob_size < 0 || b->ob_size < 0 || ++ a->ob_size > INT_MAX - b->ob_size) { ++ PyErr_SetString(PyExc_OverflowError, ++ "strings are too large to concat"); ++ return NULL; ++ } ++ + /* Inline PyObject_NewVar */ + op = (PyStringObject *)PyObject_MALLOC(sizeof(PyStringObject) + size); + if (op == NULL) diff --git a/lang/python24/files/patch-objects_tupleobject.c b/lang/python24/files/patch-objects_tupleobject.c new file mode 100644 index 000000000000..9d53d3f265a4 --- /dev/null +++ b/lang/python24/files/patch-objects_tupleobject.c @@ -0,0 +1,17 @@ +--- Objects/tupleobject.c.orig 2006-03-17 20:04:15.000000000 +0100 ++++ Objects/tupleobject.c +@@ -60,11 +60,12 @@ PyTuple_New(register int size) + int nbytes = size * sizeof(PyObject *); + /* Check for overflow */ + if (nbytes / sizeof(PyObject *) != (size_t)size || +- (nbytes += sizeof(PyTupleObject) - sizeof(PyObject *)) +- <= 0) ++ (nbytes > INT_MAX - sizeof(PyTupleObject) - sizeof(PyObject *))) + { + return PyErr_NoMemory(); + } ++ nbytes += sizeof(PyTupleObject) - sizeof(PyObject *); ++ + op = PyObject_GC_NewVar(PyTupleObject, &PyTuple_Type, size); + if (op == NULL) + return NULL; diff --git a/lang/python24/files/patch-objects_unicodeobject.c b/lang/python24/files/patch-objects_unicodeobject.c new file mode 100644 index 000000000000..55e0fc76d438 --- /dev/null +++ b/lang/python24/files/patch-objects_unicodeobject.c @@ -0,0 +1,112 @@ +--- Objects/unicodeobject.c.orig 2006-10-05 20:08:58.000000000 +0200 ++++ Objects/unicodeobject.c +@@ -186,6 +186,11 @@ PyUnicodeObject *_PyUnicode_New(int leng + return unicode_empty; + } + ++ /* Ensure we won't overflow the size. */ ++ if (length > ((INT_MAX / sizeof(Py_UNICODE)) - 1)) { ++ return (PyUnicodeObject *)PyErr_NoMemory(); ++ } ++ + /* Unicode freelist & memory allocation */ + if (unicode_freelist) { + unicode = unicode_freelist; +@@ -1040,6 +1045,9 @@ PyObject *PyUnicode_EncodeUTF7(const Py_ + char * out; + char * start; + ++ if (cbAllocated / 5 != size) ++ return PyErr_NoMemory(); ++ + if (size == 0) + return PyString_FromStringAndSize(NULL, 0); + +@@ -1638,6 +1646,7 @@ PyUnicode_EncodeUTF16(const Py_UNICODE * + { + PyObject *v; + unsigned char *p; ++ int nsize, bytesize; + #ifdef Py_UNICODE_WIDE + int i, pairs; + #else +@@ -1662,8 +1671,15 @@ PyUnicode_EncodeUTF16(const Py_UNICODE * + if (s[i] >= 0x10000) + pairs++; + #endif +- v = PyString_FromStringAndSize(NULL, +- 2 * (size + pairs + (byteorder == 0))); ++ /* 2 * (size + pairs + (byteorder == 0)) */ ++ if (size > INT_MAX || ++ size > INT_MAX - pairs - (byteorder == 0)) ++ return PyErr_NoMemory(); ++ nsize = (size + pairs + (byteorder == 0)); ++ bytesize = nsize * 2; ++ if (bytesize / 2 != nsize) ++ return PyErr_NoMemory(); ++ v = PyString_FromStringAndSize(NULL, bytesize); + if (v == NULL) + return NULL; + +@@ -1977,6 +1993,11 @@ PyObject *unicodeescape_string(const Py_ + char *p; + + static const char *hexdigit = "0123456789abcdef"; ++#ifdef Py_UNICODE_WIDE ++ const int expandsize = 10; ++#else ++ const int expandsize = 6; ++#endif + + /* Initial allocation is based on the longest-possible unichr + escape. +@@ -1992,13 +2013,12 @@ PyObject *unicodeescape_string(const Py_ + escape. + */ + ++ if (size > (INT_MAX - 2 - 1) / expandsize) ++ return PyErr_NoMemory(); ++ + repr = PyString_FromStringAndSize(NULL, + 2 +-#ifdef Py_UNICODE_WIDE +- + 10*size +-#else +- + 6*size +-#endif ++ + expandsize*size + + 1); + if (repr == NULL) + return NULL; +@@ -2239,12 +2259,16 @@ PyObject *PyUnicode_EncodeRawUnicodeEsca + char *q; + + static const char *hexdigit = "0123456789abcdef"; +- + #ifdef Py_UNICODE_WIDE +- repr = PyString_FromStringAndSize(NULL, 10 * size); ++ const int expandsize = 10; + #else +- repr = PyString_FromStringAndSize(NULL, 6 * size); ++ const int expandsize = 6; + #endif ++ ++ if (size > INT_MAX / expandsize) ++ return PyErr_NoMemory(); ++ ++ repr = PyString_FromStringAndSize(NULL, expandsize * size); + if (repr == NULL) + return NULL; + if (size == 0) +@@ -4289,6 +4313,11 @@ PyUnicodeObject *pad(PyUnicodeObject *se + return self; + } + ++ if (left > INT_MAX - self->length || ++ right > INT_MAX - (left + self->length)) { ++ PyErr_SetString(PyExc_OverflowError, "padded string is too long"); ++ return NULL; ++ } + u = _PyUnicode_New(left + self->length + right); + if (u) { + if (left) diff --git a/lang/python24/files/patch-python_mysnprintf.c b/lang/python24/files/patch-python_mysnprintf.c new file mode 100644 index 000000000000..84b1d41f2b36 --- /dev/null +++ b/lang/python24/files/patch-python_mysnprintf.c @@ -0,0 +1,55 @@ +--- Python/mysnprintf.c.orig 2001-12-21 17:32:15.000000000 +0100 ++++ Python/mysnprintf.c +@@ -54,18 +54,28 @@ int + PyOS_vsnprintf(char *str, size_t size, const char *format, va_list va) + { + int len; /* # bytes written, excluding \0 */ +-#ifndef HAVE_SNPRINTF ++#ifdef HAVE_SNPRINTF ++#define _PyOS_vsnprintf_EXTRA_SPACE 1 ++#else ++#define _PyOS_vsnprintf_EXTRA_SPACE 512 + char *buffer; + #endif + assert(str != NULL); + assert(size > 0); + assert(format != NULL); ++ /* We take a size_t as input but return an int. Sanity check ++ * our input so that it won't cause an overflow in the ++ * vsnprintf return value or the buffer malloc size. */ ++ if (size > INT_MAX - _PyOS_vsnprintf_EXTRA_SPACE) { ++ len = -666; ++ goto Done; ++ } + + #ifdef HAVE_SNPRINTF + len = vsnprintf(str, size, format, va); + #else + /* Emulate it. */ +- buffer = PyMem_MALLOC(size + 512); ++ buffer = PyMem_MALLOC(size + _PyOS_vsnprintf_EXTRA_SPACE); + if (buffer == NULL) { + len = -666; + goto Done; +@@ -75,7 +85,7 @@ PyOS_vsnprintf(char *str, size_t size, c + if (len < 0) + /* ignore the error */; + +- else if ((size_t)len >= size + 512) ++ else if ((size_t)len >= size + _PyOS_vsnprintf_EXTRA_SPACE) + Py_FatalError("Buffer overflow in PyOS_snprintf/PyOS_vsnprintf"); + + else { +@@ -86,8 +96,10 @@ PyOS_vsnprintf(char *str, size_t size, c + str[to_copy] = '\0'; + } + PyMem_FREE(buffer); +-Done: + #endif +- str[size-1] = '\0'; ++Done: ++ if (size > 0) ++ str[size-1] = '\0'; + return len; ++#undef _PyOS_vsnprintf_EXTRA_SPACE + } |