From e6bbb4d16f32e4d243897f25b0ad01f81498e095 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20v=2E=20L=C3=B6wis?= Date: Sat, 3 May 2003 10:00:22 +0000 Subject: [PATCH] Patch #684981: Add cleanup capability for argument parsers. Fixes 501716. --- Python/getargs.c | 118 ++++++++++++++++++++++++++++++++++++----------- 1 file changed, 90 insertions(+), 28 deletions(-) diff --git a/Python/getargs.c b/Python/getargs.c index 237a29dc06a..72194a86a0e 100644 --- a/Python/getargs.c +++ b/Python/getargs.c @@ -17,10 +17,11 @@ int PyArg_ParseTupleAndKeywords(PyObject *, PyObject *, static int vgetargs1(PyObject *, char *, va_list *, int); static void seterror(int, char *, int *, char *, char *); static char *convertitem(PyObject *, char **, va_list *, int *, char *, - size_t); + size_t, PyObject **); static char *converttuple(PyObject *, char **, va_list *, - int *, char *, size_t, int); -static char *convertsimple(PyObject *, char **, va_list *, char *, size_t); + int *, char *, size_t, int, PyObject **); +static char *convertsimple(PyObject *, char **, va_list *, char *, + size_t, PyObject **); static int convertbuffer(PyObject *, void **p, char **); static int vgetargskeywords(PyObject *, PyObject *, @@ -72,6 +73,49 @@ PyArg_VaParse(PyObject *args, char *format, va_list va) } +/* Handle cleanup of allocated memory in case of exception */ + +static int +addcleanup(void *ptr, PyObject **freelist) +{ + PyObject *cobj; + if (!*freelist) { + *freelist = PyList_New(0); + if (!*freelist) { + PyMem_FREE(ptr); + return -1; + } + } + cobj = PyCObject_FromVoidPtr(ptr, NULL); + if (!cobj) { + PyMem_FREE(ptr); + return -1; + } + if(PyList_Append(*freelist, cobj)) { + PyMem_FREE(ptr); + Py_DECREF(cobj); + return -1; + } + Py_DECREF(cobj); + return 0; +} + +static int +cleanreturn(int retval, PyObject *freelist) +{ + if(freelist) { + if((retval) == 0) { + int len = PyList_GET_SIZE(freelist), i; + for (i = 0; i < len; i++) + PyMem_FREE(PyCObject_AsVoidPtr( + PyList_GET_ITEM(freelist, i))); + } + Py_DECREF(freelist); + } + return retval; +} + + static int vgetargs1(PyObject *args, char *format, va_list *p_va, int compat) { @@ -86,6 +130,7 @@ vgetargs1(PyObject *args, char *format, va_list *p_va, int compat) char *formatsave = format; int i, len; char *msg; + PyObject *freelist = NULL; assert(compat || (args != (PyObject*)NULL)); @@ -157,11 +202,11 @@ vgetargs1(PyObject *args, char *format, va_list *p_va, int compat) return 0; } msg = convertitem(args, &format, p_va, levels, msgbuf, - sizeof(msgbuf)); + sizeof(msgbuf), &freelist); if (msg == NULL) - return 1; + return cleanreturn(1, freelist); seterror(levels[0], msg, levels+1, fname, message); - return 0; + return cleanreturn(0, freelist); } else { PyErr_SetString(PyExc_SystemError, @@ -200,10 +245,10 @@ vgetargs1(PyObject *args, char *format, va_list *p_va, int compat) if (*format == '|') format++; msg = convertitem(PyTuple_GET_ITEM(args, i), &format, p_va, - levels, msgbuf, sizeof(msgbuf)); + levels, msgbuf, sizeof(msgbuf), &freelist); if (msg) { seterror(i+1, msg, levels, fname, message); - return 0; + return cleanreturn(0, freelist); } } @@ -212,10 +257,10 @@ vgetargs1(PyObject *args, char *format, va_list *p_va, int compat) *format != '|' && *format != ':' && *format != ';') { PyErr_Format(PyExc_SystemError, "bad format string: %.200s", formatsave); - return 0; + return cleanreturn(0, freelist); } - return 1; + return cleanreturn(1, freelist); } @@ -277,7 +322,7 @@ seterror(int iarg, char *msg, int *levels, char *fname, char *message) static char * converttuple(PyObject *arg, char **p_format, va_list *p_va, int *levels, - char *msgbuf, size_t bufsize, int toplevel) + char *msgbuf, size_t bufsize, int toplevel, PyObject **freelist) { int level = 0; int n = 0; @@ -327,7 +372,7 @@ converttuple(PyObject *arg, char **p_format, va_list *p_va, int *levels, PyObject *item; item = PySequence_GetItem(arg, i); msg = convertitem(item, &format, p_va, levels+1, msgbuf, - bufsize); + bufsize, freelist); /* PySequence_GetItem calls tp->sq_item, which INCREFs */ Py_XDECREF(item); if (msg != NULL) { @@ -345,7 +390,7 @@ converttuple(PyObject *arg, char **p_format, va_list *p_va, int *levels, static char * convertitem(PyObject *arg, char **p_format, va_list *p_va, int *levels, - char *msgbuf, size_t bufsize) + char *msgbuf, size_t bufsize, PyObject **freelist) { char *msg; char *format = *p_format; @@ -353,12 +398,13 @@ convertitem(PyObject *arg, char **p_format, va_list *p_va, int *levels, if (*format == '(' /* ')' */) { format++; msg = converttuple(arg, &format, p_va, levels, msgbuf, - bufsize, 0); + bufsize, 0, freelist); if (msg == NULL) format++; } else { - msg = convertsimple(arg, &format, p_va, msgbuf, bufsize); + msg = convertsimple(arg, &format, p_va, msgbuf, bufsize, + freelist); if (msg != NULL) levels[0] = 0; } @@ -409,7 +455,7 @@ float_argument_error(PyObject *arg) static char * convertsimple(PyObject *arg, char **p_format, va_list *p_va, char *msgbuf, - size_t bufsize) + size_t bufsize, PyObject **freelist) { char *format = *p_format; char c = *format++; @@ -836,10 +882,12 @@ convertsimple(PyObject *arg, char **p_format, va_list *p_va, char *msgbuf, int *buffer_len = va_arg(*p_va, int *); format++; - if (buffer_len == NULL) + if (buffer_len == NULL) { + Py_DECREF(s); return converterr( "(buffer_len is NULL)", arg, msgbuf, bufsize); + } if (*buffer == NULL) { *buffer = PyMem_NEW(char, size + 1); if (*buffer == NULL) { @@ -848,6 +896,12 @@ convertsimple(PyObject *arg, char **p_format, va_list *p_va, char *msgbuf, "(memory error)", arg, msgbuf, bufsize); } + if(addcleanup(*buffer, freelist)) { + Py_DECREF(s); + return converterr( + "(cleanup problem)", + arg, msgbuf, bufsize); + } } else { if (size + 1 > *buffer_len) { Py_DECREF(s); @@ -874,16 +928,23 @@ convertsimple(PyObject *arg, char **p_format, va_list *p_va, char *msgbuf, PyMem_Free()ing it after usage */ - if ((int)strlen(PyString_AS_STRING(s)) != size) + if ((int)strlen(PyString_AS_STRING(s)) != size) { + Py_DECREF(s); return converterr( "(encoded string without NULL bytes)", arg, msgbuf, bufsize); + } *buffer = PyMem_NEW(char, size + 1); if (*buffer == NULL) { Py_DECREF(s); return converterr("(memory error)", arg, msgbuf, bufsize); } + if(addcleanup(*buffer, freelist)) { + Py_DECREF(s); + return converterr("(cleanup problem)", + arg, msgbuf, bufsize); + } memcpy(*buffer, PyString_AS_STRING(s), size + 1); @@ -1103,6 +1164,7 @@ vgetargskeywords(PyObject *args, PyObject *keywords, char *format, char *formatsave; int i, len, nargs, nkeywords; char *msg, **p; + PyObject *freelist = NULL; assert(args != NULL && PyTuple_Check(args)); assert(keywords == NULL || PyDict_Check(keywords)); @@ -1227,16 +1289,16 @@ vgetargskeywords(PyObject *args, PyObject *keywords, char *format, if (*format == '|') format++; msg = convertitem(PyTuple_GET_ITEM(args, i), &format, p_va, - levels, msgbuf, sizeof(msgbuf)); + levels, msgbuf, sizeof(msgbuf), &freelist); if (msg) { seterror(i+1, msg, levels, fname, message); - return 0; + return cleanreturn(0, freelist); } } /* handle no keyword parameters in call */ if (nkeywords == 0) - return 1; + return cleanreturn(1, freelist); /* convert the keyword arguments; this uses the format string where it was left after processing args */ @@ -1248,23 +1310,23 @@ vgetargskeywords(PyObject *args, PyObject *keywords, char *format, if (item != NULL) { Py_INCREF(item); msg = convertitem(item, &format, p_va, levels, msgbuf, - sizeof(msgbuf)); + sizeof(msgbuf), &freelist); Py_DECREF(item); if (msg) { seterror(i+1, msg, levels, fname, message); - return 0; + return cleanreturn(0, freelist); } --nkeywords; if (nkeywords == 0) break; } else if (PyErr_Occurred()) - return 0; + return cleanreturn(0, freelist); else { msg = skipitem(&format, p_va); if (msg) { seterror(i+1, msg, levels, fname, message); - return 0; + return cleanreturn(0, freelist); } } } @@ -1279,7 +1341,7 @@ vgetargskeywords(PyObject *args, PyObject *keywords, char *format, if (!PyString_Check(key)) { PyErr_SetString(PyExc_TypeError, "keywords must be strings"); - return 0; + return cleanreturn(0, freelist); } ks = PyString_AsString(key); for (i = 0; i < max; i++) { @@ -1293,12 +1355,12 @@ vgetargskeywords(PyObject *args, PyObject *keywords, char *format, "'%s' is an invalid keyword " "argument for this function", ks); - return 0; + return cleanreturn(0, freelist); } } } - return 1; + return cleanreturn(1, freelist); }