summaryrefslogtreecommitdiffstats
path: root/Python
diff options
context:
space:
mode:
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>2021-08-10 13:47:23 (GMT)
committerGitHub <noreply@github.com>2021-08-10 13:47:23 (GMT)
commitd86bbe3cff0abefc13e5462cca1fb3344d4a5b52 (patch)
tree8190c898580634deb56b37b4de7107d191b10422 /Python
parent52d481f15c953e06155e65ca823c8f6cae7a6b65 (diff)
downloadcpython-d86bbe3cff0abefc13e5462cca1fb3344d4a5b52.zip
cpython-d86bbe3cff0abefc13e5462cca1fb3344d4a5b52.tar.gz
cpython-d86bbe3cff0abefc13e5462cca1fb3344d4a5b52.tar.bz2
bpo-25782: avoid hang in PyErr_SetObject when current exception has a cycle in its context chain (GH-27626)
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.c16
1 files changed, 15 insertions, 1 deletions
diff --git a/Python/errors.c b/Python/errors.c
index d4b9db1..9944c3a 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);
}