mirror of
https://github.com/python/cpython.git
synced 2025-08-03 16:39:00 +00:00
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
This commit is contained in:
parent
6b37d0d530
commit
d5c217475c
3 changed files with 158 additions and 1 deletions
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue