Issue #10987: Fix the recursion limit handling in the _pickle module.

This commit is contained in:
Antoine Pitrou 2011-01-23 17:12:25 +00:00
parent 0929b1fc70
commit e6d4c5bab8
3 changed files with 24 additions and 14 deletions

View File

@ -16,6 +16,8 @@ Core and Builtins
Library Library
------- -------
- Issue #10987: Fix the recursion limit handling in the _pickle module.
- Issue #10983: Fix several bugs making tunnel requests in http.client. - Issue #10983: Fix several bugs making tunnel requests in http.client.
- Issue #10955: zipimport uses ASCII encoding instead of cp437 to decode - Issue #10955: zipimport uses ASCII encoding instead of cp437 to decode

View File

@ -2244,19 +2244,21 @@ save_list(PicklerObject *self, PyObject *obj)
if (len != 0) { if (len != 0) {
/* Materialize the list elements. */ /* Materialize the list elements. */
if (PyList_CheckExact(obj) && self->proto > 0) { if (PyList_CheckExact(obj) && self->proto > 0) {
if (Py_EnterRecursiveCall(" while pickling an object") == 0) { if (Py_EnterRecursiveCall(" while pickling an object"))
status = batch_list_exact(self, obj); goto error;
Py_LeaveRecursiveCall(); status = batch_list_exact(self, obj);
} Py_LeaveRecursiveCall();
} else { } else {
PyObject *iter = PyObject_GetIter(obj); PyObject *iter = PyObject_GetIter(obj);
if (iter == NULL) if (iter == NULL)
goto error; goto error;
if (Py_EnterRecursiveCall(" while pickling an object") == 0) { if (Py_EnterRecursiveCall(" while pickling an object")) {
status = batch_list(self, iter); Py_DECREF(iter);
Py_LeaveRecursiveCall(); goto error;
} }
status = batch_list(self, iter);
Py_LeaveRecursiveCall();
Py_DECREF(iter); Py_DECREF(iter);
} }
} }
@ -2504,10 +2506,10 @@ save_dict(PicklerObject *self, PyObject *obj)
if (PyDict_CheckExact(obj) && self->proto > 0) { if (PyDict_CheckExact(obj) && self->proto > 0) {
/* We can take certain shortcuts if we know this is a dict and /* We can take certain shortcuts if we know this is a dict and
not a dict subclass. */ not a dict subclass. */
if (Py_EnterRecursiveCall(" while pickling an object") == 0) { if (Py_EnterRecursiveCall(" while pickling an object"))
status = batch_dict_exact(self, obj); goto error;
Py_LeaveRecursiveCall(); status = batch_dict_exact(self, obj);
} Py_LeaveRecursiveCall();
} else { } else {
items = PyObject_CallMethod(obj, "items", "()"); items = PyObject_CallMethod(obj, "items", "()");
if (items == NULL) if (items == NULL)
@ -2516,7 +2518,12 @@ save_dict(PicklerObject *self, PyObject *obj)
Py_DECREF(items); Py_DECREF(items);
if (iter == NULL) if (iter == NULL)
goto error; goto error;
if (Py_EnterRecursiveCall(" while pickling an object")) {
Py_DECREF(iter);
goto error;
}
status = batch_dict(self, iter); status = batch_dict(self, iter);
Py_LeaveRecursiveCall();
Py_DECREF(iter); Py_DECREF(iter);
} }
} }
@ -3044,7 +3051,7 @@ save(PicklerObject *self, PyObject *obj, int pers_save)
PyObject *reduce_value = NULL; PyObject *reduce_value = NULL;
int status = 0; int status = 0;
if (Py_EnterRecursiveCall(" while pickling an object") < 0) if (Py_EnterRecursiveCall(" while pickling an object"))
return -1; return -1;
/* The extra pers_save argument is necessary to avoid calling save_pers() /* The extra pers_save argument is necessary to avoid calling save_pers()

View File

@ -77,14 +77,15 @@ def test_cpickle(_cache={}):
except ImportError: except ImportError:
print("cannot import _pickle, skipped!") print("cannot import _pickle, skipped!")
return return
l = None k, l = None, None
for n in itertools.count(): for n in itertools.count():
try: try:
l = _cache[n] l = _cache[n]
continue # Already tried and it works, let's save some time continue # Already tried and it works, let's save some time
except KeyError: except KeyError:
for i in range(100): for i in range(100):
l = [l] l = [k, l]
k = {i: l}
_pickle.Pickler(io.BytesIO(), protocol=-1).dump(l) _pickle.Pickler(io.BytesIO(), protocol=-1).dump(l)
_cache[n] = l _cache[n] = l