summaryrefslogtreecommitdiffstats
path: root/Python/errors.c
diff options
context:
space:
mode:
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>2021-08-10 11:08:41 (GMT)
committerGitHub <noreply@github.com>2021-08-10 11:08:41 (GMT)
commit6f4cdeddb97532144f93ca37b8b21451f445c7bf (patch)
tree04f25eeb99d2c825e7a4a8a6b402988b71114016 /Python/errors.c
parentc7dfbd2f413eb76cdbd44f44d698e9a399fdcbd5 (diff)
downloadcpython-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/errors.c')
-rw-r--r--Python/errors.c16
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);
}