diff options
author | Guido van Rossum <guido@python.org> | 2000-04-21 21:17:39 (GMT) |
---|---|---|
committer | Guido van Rossum <guido@python.org> | 2000-04-21 21:17:39 (GMT) |
commit | 25826c93c4cf1fcac537e6cded5ce986c751134e (patch) | |
tree | 58061e8b687c1fbb76c77d1926884d053550c8b4 | |
parent | 5ce78f8e4e2522ab59f4c2c35a5a784dcc2dafc8 (diff) | |
download | cpython-25826c93c4cf1fcac537e6cded5ce986c751134e.zip cpython-25826c93c4cf1fcac537e6cded5ce986c751134e.tar.gz cpython-25826c93c4cf1fcac537e6cded5ce986c751134e.tar.bz2 |
Charles Waldman writes:
"""
Running "test_extcall" repeatedly results in memory leaks.
One of these can't be fixed (at least not easily!), it happens since
this code:
def saboteur(**kw):
kw['x'] = locals()
d = {}
saboteur(a=1, **d)
creates a circular reference - d['x']['d']==d
The others are due to some missing decrefs in ceval.c, fixed by the
patch attached below.
Note: I originally wrote this without the "goto", just adding the
missing decref's where needed. But I think the goto is justified in
keeping the executable code size of ceval as small as possible.
"""
[I think the circular reference is more like kw['x']['kw'] == kw. --GvR]
-rw-r--r-- | Python/ceval.c | 27 |
1 files changed, 13 insertions, 14 deletions
diff --git a/Python/ceval.c b/Python/ceval.c index 989e17f..d0958bd 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -1623,8 +1623,7 @@ eval_code2(co, globals, locals, if (!PyDict_Check(kwdict)) { PyErr_SetString(PyExc_TypeError, "** argument must be a dictionary"); - x = NULL; - break; + goto extcall_fail; } } if (flags & 1) { @@ -1632,39 +1631,34 @@ eval_code2(co, globals, locals, if (!PySequence_Check(stararg)) { PyErr_SetString(PyExc_TypeError, "* argument must be a sequence"); - x = NULL; - break; + goto extcall_fail; } /* Convert abstract sequence to concrete tuple */ if (!PyTuple_Check(stararg)) { PyObject *t = NULL; t = PySequence_Tuple(stararg); if (t == NULL) { - x = NULL; - break; + goto extcall_fail; } Py_DECREF(stararg); stararg = t; } nstar = PyTuple_GET_SIZE(stararg); if (nstar < 0) { - x = NULL; - break; + goto extcall_fail; } } if (nk > 0) { if (kwdict == NULL) { kwdict = PyDict_New(); if (kwdict == NULL) { - x = NULL; - break; + goto extcall_fail; } } else { PyObject *d = PyDict_Copy(kwdict); if (d == NULL) { - x = NULL; - break; + goto extcall_fail; } Py_DECREF(kwdict); kwdict = d; @@ -1680,7 +1674,7 @@ eval_code2(co, globals, locals, PyString_AsString(key)); Py_DECREF(key); Py_DECREF(value); - break; + goto extcall_fail; } err = PyDict_SetItem(kwdict, key, value); Py_DECREF(key); @@ -1689,7 +1683,11 @@ eval_code2(co, globals, locals, break; } if (err) { - Py_DECREF(kwdict); + extcall_fail: + Py_XDECREF(kwdict); + Py_XDECREF(stararg); + Py_DECREF(func); + x=NULL; break; } } @@ -2382,6 +2380,7 @@ PyEval_CallObjectWithKeywords(func, arg, kw) if (kw != NULL && !PyDict_Check(kw)) { PyErr_SetString(PyExc_TypeError, "keyword list must be a dictionary"); + Py_DECREF(arg); return NULL; } |