]> granicus.if.org Git - python/commitdiff
Patch #684981: Add cleanup capability for argument parsers. Fixes 501716.
authorMartin v. Löwis <martin@v.loewis.de>
Sat, 3 May 2003 10:00:22 +0000 (10:00 +0000)
committerMartin v. Löwis <martin@v.loewis.de>
Sat, 3 May 2003 10:00:22 +0000 (10:00 +0000)
Python/getargs.c

index 237a29dc06a733e57ab4e295aec1c60babdcb1b9..72194a86a0e3cc148672df75f41ae3c3023707c5 100644 (file)
@@ -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);
 }