diff options
author | Miss Islington (bot) <31488909+miss-islington@users.noreply.github.com> | 2021-08-10 11:08:41 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-08-10 11:08:41 (GMT) |
commit | 6f4cdeddb97532144f93ca37b8b21451f445c7bf (patch) | |
tree | 04f25eeb99d2c825e7a4a8a6b402988b71114016 /Python | |
parent | c7dfbd2f413eb76cdbd44f44d698e9a399fdcbd5 (diff) | |
download | cpython-6f4cdeddb97532144f93ca37b8b21451f445c7bf.zip cpython-6f4cdeddb97532144f93ca37b8b21451f445c7bf.tar.gz cpython-6f4cdeddb97532144f93ca37b8b21451f445c7bf.tar.bz2 |
bpo-25782: avoid hang in PyErr_SetObject when current exception has a cycle in its context chain (GH-27626) (GH-27707)
Co-authored-by: Dennis Sweeney 36520290+sweeneyde@users.noreply.github.com
(cherry picked from commit d5c217475c4957a8084ac3f92ae012ece5edc7cb)
Co-authored-by: Irit Katriel <1055913+iritkatriel@users.noreply.github.com>
Diffstat (limited to 'Python')
-rw-r--r-- | Python/errors.c | 16 |
1 files changed, 15 insertions, 1 deletions
diff --git a/Python/errors.c b/Python/errors.c index 2c020cd..8a2ba8f 100644 --- a/Python/errors.c +++ b/Python/errors.c @@ -148,12 +148,16 @@ _PyErr_SetObject(PyThreadState *tstate, PyObject *exception, PyObject *value) value = fixed_value; } - /* Avoid reference cycles through the context chain. + /* Avoid creating new reference cycles through the + context chain, while taking care not to hang on + pre-existing ones. This is O(chain length) but context chains are usually very short. Sensitive readers may try to inline the call to PyException_GetContext. */ if (exc_value != value) { PyObject *o = exc_value, *context; + PyObject *slow_o = o; /* Floyd's cycle detection algo */ + int slow_update_toggle = 0; while ((context = PyException_GetContext(o))) { Py_DECREF(context); if (context == value) { @@ -161,6 +165,16 @@ _PyErr_SetObject(PyThreadState *tstate, PyObject *exception, PyObject *value) break; } o = context; + if (o == slow_o) { + /* pre-existing cycle - all exceptions on the + path were visited and checked. */ + break; + } + if (slow_update_toggle) { + slow_o = PyException_GetContext(slow_o); + Py_DECREF(slow_o); + } + slow_update_toggle = !slow_update_toggle; } PyException_SetContext(value, exc_value); } |