diff options
author | Antoine Pitrou <solipsis@pitrou.net> | 2011-01-23 17:12:25 (GMT) |
---|---|---|
committer | Antoine Pitrou <solipsis@pitrou.net> | 2011-01-23 17:12:25 (GMT) |
commit | e6d4c5bab8d18e32bba6482da1b603b35f2fe254 (patch) | |
tree | b2d2dfb60696e0c9e0a36c903f14c458a0dda1fe | |
parent | 0929b1fc70e2f3fd1c4550ebbcaa4e733f5a8f7a (diff) | |
download | cpython-e6d4c5bab8d18e32bba6482da1b603b35f2fe254.zip cpython-e6d4c5bab8d18e32bba6482da1b603b35f2fe254.tar.gz cpython-e6d4c5bab8d18e32bba6482da1b603b35f2fe254.tar.bz2 |
Issue #10987: Fix the recursion limit handling in the _pickle module.
-rw-r--r-- | Misc/NEWS | 2 | ||||
-rw-r--r-- | Modules/_pickle.c | 31 | ||||
-rw-r--r-- | Tools/scripts/find_recursionlimit.py | 5 |
3 files changed, 24 insertions, 14 deletions
@@ -16,6 +16,8 @@ Core and Builtins Library ------- +- Issue #10987: Fix the recursion limit handling in the _pickle module. + - Issue #10983: Fix several bugs making tunnel requests in http.client. - Issue #10955: zipimport uses ASCII encoding instead of cp437 to decode diff --git a/Modules/_pickle.c b/Modules/_pickle.c index 0ef1f22..b01a8b2 100644 --- a/Modules/_pickle.c +++ b/Modules/_pickle.c @@ -2244,19 +2244,21 @@ save_list(PicklerObject *self, PyObject *obj) if (len != 0) { /* Materialize the list elements. */ if (PyList_CheckExact(obj) && self->proto > 0) { - if (Py_EnterRecursiveCall(" while pickling an object") == 0) { - status = batch_list_exact(self, obj); - Py_LeaveRecursiveCall(); - } + if (Py_EnterRecursiveCall(" while pickling an object")) + goto error; + status = batch_list_exact(self, obj); + Py_LeaveRecursiveCall(); } else { PyObject *iter = PyObject_GetIter(obj); if (iter == NULL) goto error; - if (Py_EnterRecursiveCall(" while pickling an object") == 0) { - status = batch_list(self, iter); - Py_LeaveRecursiveCall(); + if (Py_EnterRecursiveCall(" while pickling an object")) { + Py_DECREF(iter); + goto error; } + status = batch_list(self, iter); + Py_LeaveRecursiveCall(); Py_DECREF(iter); } } @@ -2504,10 +2506,10 @@ save_dict(PicklerObject *self, PyObject *obj) if (PyDict_CheckExact(obj) && self->proto > 0) { /* We can take certain shortcuts if we know this is a dict and not a dict subclass. */ - if (Py_EnterRecursiveCall(" while pickling an object") == 0) { - status = batch_dict_exact(self, obj); - Py_LeaveRecursiveCall(); - } + if (Py_EnterRecursiveCall(" while pickling an object")) + goto error; + status = batch_dict_exact(self, obj); + Py_LeaveRecursiveCall(); } else { items = PyObject_CallMethod(obj, "items", "()"); if (items == NULL) @@ -2516,7 +2518,12 @@ save_dict(PicklerObject *self, PyObject *obj) Py_DECREF(items); if (iter == NULL) goto error; + if (Py_EnterRecursiveCall(" while pickling an object")) { + Py_DECREF(iter); + goto error; + } status = batch_dict(self, iter); + Py_LeaveRecursiveCall(); Py_DECREF(iter); } } @@ -3044,7 +3051,7 @@ save(PicklerObject *self, PyObject *obj, int pers_save) PyObject *reduce_value = NULL; int status = 0; - if (Py_EnterRecursiveCall(" while pickling an object") < 0) + if (Py_EnterRecursiveCall(" while pickling an object")) return -1; /* The extra pers_save argument is necessary to avoid calling save_pers() diff --git a/Tools/scripts/find_recursionlimit.py b/Tools/scripts/find_recursionlimit.py index b299bf5..443f052 100644 --- a/Tools/scripts/find_recursionlimit.py +++ b/Tools/scripts/find_recursionlimit.py @@ -77,14 +77,15 @@ def test_cpickle(_cache={}): except ImportError: print("cannot import _pickle, skipped!") return - l = None + k, l = None, None for n in itertools.count(): try: l = _cache[n] continue # Already tried and it works, let's save some time except KeyError: for i in range(100): - l = [l] + l = [k, l] + k = {i: l} _pickle.Pickler(io.BytesIO(), protocol=-1).dump(l) _cache[n] = l |