This is Pete Shinners' patch from his bug report

[ 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.
This commit is contained in:
Michael W. Hudson 2004-07-14 11:28:06 +00:00
parent 8cec3ab0e4
commit c849e63eb0
1 changed files with 30 additions and 10 deletions

View File

@ -152,28 +152,32 @@ do_mkdict(char **p_format, va_list *p_va, int endchar, int n)
{ {
PyObject *d; PyObject *d;
int i; int i;
int itemfailed = 0;
if (n < 0) if (n < 0)
return NULL; return NULL;
if ((d = PyDict_New()) == NULL) if ((d = PyDict_New()) == NULL)
return 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) { for (i = 0; i < n; i+= 2) {
PyObject *k, *v; PyObject *k, *v;
int err; int err;
k = do_mkvalue(p_format, p_va); k = do_mkvalue(p_format, p_va);
if (k == NULL) { if (k == NULL) {
Py_DECREF(d); itemfailed = 1;
return NULL; Py_INCREF(Py_None);
k = Py_None;
} }
v = do_mkvalue(p_format, p_va); v = do_mkvalue(p_format, p_va);
if (v == NULL) { if (v == NULL) {
Py_DECREF(k); itemfailed = 1;
Py_DECREF(d); Py_INCREF(Py_None);
return NULL; v = Py_None;
} }
err = PyDict_SetItem(d, k, v); err = PyDict_SetItem(d, k, v);
Py_DECREF(k); Py_DECREF(k);
Py_DECREF(v); Py_DECREF(v);
if (err < 0) { if (err < 0 || itemfailed) {
Py_DECREF(d); Py_DECREF(d);
return NULL; return NULL;
} }
@ -194,15 +198,19 @@ do_mklist(char **p_format, va_list *p_va, int endchar, int n)
{ {
PyObject *v; PyObject *v;
int i; int i;
int itemfailed = 0;
if (n < 0) if (n < 0)
return NULL; return NULL;
if ((v = PyList_New(n)) == NULL) if ((v = PyList_New(n)) == NULL)
return 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++) { for (i = 0; i < n; i++) {
PyObject *w = do_mkvalue(p_format, p_va); PyObject *w = do_mkvalue(p_format, p_va);
if (w == NULL) { if (w == NULL) {
Py_DECREF(v); itemfailed = 1;
return NULL; Py_INCREF(Py_None);
w = Py_None;
} }
PyList_SetItem(v, i, w); 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) else if (endchar)
++*p_format; ++*p_format;
if (itemfailed) {
Py_DECREF(v);
v = NULL;
}
return v; return v;
} }
@ -233,15 +245,19 @@ do_mktuple(char **p_format, va_list *p_va, int endchar, int n)
{ {
PyObject *v; PyObject *v;
int i; int i;
int itemfailed = 0;
if (n < 0) if (n < 0)
return NULL; return NULL;
if ((v = PyTuple_New(n)) == NULL) if ((v = PyTuple_New(n)) == NULL)
return 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++) { for (i = 0; i < n; i++) {
PyObject *w = do_mkvalue(p_format, p_va); PyObject *w = do_mkvalue(p_format, p_va);
if (w == NULL) { if (w == NULL) {
Py_DECREF(v); itemfailed = 1;
return NULL; Py_INCREF(Py_None);
w = Py_None;
} }
PyTuple_SetItem(v, i, w); 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) else if (endchar)
++*p_format; ++*p_format;
if (itemfailed) {
Py_DECREF(v);
v = NULL;
}
return v; return v;
} }