]> granicus.if.org Git - python/commitdiff
This is Pete Shinners' patch from his bug report
authorMichael W. Hudson <mwh@python.net>
Wed, 14 Jul 2004 11:28:06 +0000 (11:28 +0000)
committerMichael W. Hudson <mwh@python.net>
Wed, 14 Jul 2004 11:28:06 +0000 (11:28 +0000)
[ 984722 ] Py_BuildValue loses reference counts on error

I'm ever-so-slightly uneasy at the amount of work this can do with an
exception pending, but I don't think that this can result in anything
more serious than a strange error message.

Python/modsupport.c

index f26d7b8eca2a181852cb67c6c3495353b9dd8eb9..197d99b1d1f82cd66065a68ef1dcbe93ecc83a56 100644 (file)
@@ -152,28 +152,32 @@ do_mkdict(char **p_format, va_list *p_va, int endchar, int n)
 {
        PyObject *d;
        int i;
+       int itemfailed = 0;
        if (n < 0)
                return NULL;
        if ((d = PyDict_New()) == NULL)
                return NULL;
+       /* Note that we can't bail immediately on error as this will leak
+          refcounts on any 'N' arguments. */
        for (i = 0; i < n; i+= 2) {
                PyObject *k, *v;
                int err;
                k = do_mkvalue(p_format, p_va);
                if (k == NULL) {
-                       Py_DECREF(d);
-                       return NULL;
+                       itemfailed = 1;
+                       Py_INCREF(Py_None);
+                       k = Py_None;
                }
                v = do_mkvalue(p_format, p_va);
                if (v == NULL) {
-                       Py_DECREF(k);
-                       Py_DECREF(d);
-                       return NULL;
+                       itemfailed = 1;
+                       Py_INCREF(Py_None);
+                       v = Py_None;
                }
                err = PyDict_SetItem(d, k, v);
                Py_DECREF(k);
                Py_DECREF(v);
-               if (err < 0) {
+               if (err < 0 || itemfailed) {
                        Py_DECREF(d);
                        return NULL;
                }
@@ -194,15 +198,19 @@ do_mklist(char **p_format, va_list *p_va, int endchar, int n)
 {
        PyObject *v;
        int i;
+       int itemfailed = 0;
        if (n < 0)
                return NULL;
        if ((v = PyList_New(n)) == NULL)
                return NULL;
+       /* Note that we can't bail immediately on error as this will leak
+          refcounts on any 'N' arguments. */
        for (i = 0; i < n; i++) {
                PyObject *w = do_mkvalue(p_format, p_va);
                if (w == NULL) {
-                       Py_DECREF(v);
-                       return NULL;
+                       itemfailed = 1;
+                       Py_INCREF(Py_None);
+                       w = Py_None;
                }
                PyList_SetItem(v, i, w);
        }
@@ -214,6 +222,10 @@ do_mklist(char **p_format, va_list *p_va, int endchar, int n)
        }
        else if (endchar)
                ++*p_format;
+       if (itemfailed) {
+               Py_DECREF(v);
+               v = NULL;
+       }
        return v;
 }
 
@@ -233,15 +245,19 @@ do_mktuple(char **p_format, va_list *p_va, int endchar, int n)
 {
        PyObject *v;
        int i;
+       int itemfailed = 0;
        if (n < 0)
                return NULL;
        if ((v = PyTuple_New(n)) == NULL)
                return NULL;
+       /* Note that we can't bail immediately on error as this will leak
+          refcounts on any 'N' arguments. */
        for (i = 0; i < n; i++) {
                PyObject *w = do_mkvalue(p_format, p_va);
                if (w == NULL) {
-                       Py_DECREF(v);
-                       return NULL;
+                       itemfailed = 1;
+                       Py_INCREF(Py_None);
+                       w = Py_None;
                }
                PyTuple_SetItem(v, i, w);
        }
@@ -253,6 +269,10 @@ do_mktuple(char **p_format, va_list *p_va, int endchar, int n)
        }
        else if (endchar)
                ++*p_format;
+       if (itemfailed) {
+               Py_DECREF(v);
+               v = NULL;
+       }
        return v;
 }