Skip to content

Commit 0ad0eac

Browse files
author
Anselm Kruis
committed
Issue python#117: bring the handling of caught exceptions in line with C-Python
Exception handling now follows suit the code of sys.exc_clear() and ceval.c set_exc_info(). This change helps to rule out reference leaks caused by inappropriate handling of traceback objects. https://bitbucket.org/stackless-dev/stackless/issues/117 (grafted from 36fc9e84a48999378a73173c179ba6beeabcf821)
1 parent d5696be commit 0ad0eac

File tree

2 files changed

+48
-6
lines changed

2 files changed

+48
-6
lines changed

Stackless/changelog.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ What's New in Stackless 3.X.X?
2121
- https://bitbucket.org/stackless-dev/stackless/issues/117
2222
Fix various reference leaks:
2323
- Leak of a reference to Py_None in generator.throw()
24+
25+
Additionally this change brings the handling of caught exceptions more in
26+
line with C-Python.
2427

2528
- https://bitbucket.org/stackless-dev/stackless/issues/111
2629
Restore the Python ABI function PyGen_New(). Previously Stackless named this

Stackless/module/scheduling.c

Lines changed: 45 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -553,14 +553,31 @@ kill_wrap_bad_guy(PyTaskletObject *prev, PyTaskletObject *bad_guy)
553553
PyObject *
554554
slp_restore_exception(PyFrameObject *f, int exc, PyObject *retval)
555555
{
556+
PyObject *tmp_type, *tmp_value, *tmp_tb;
556557
PyThreadState *ts = PyThreadState_GET();
557558
PyCFrameObject *cf = (PyCFrameObject *) f;
558559

560+
if (cf->ob1 == NULL) {
561+
/* set_exc_info in ceval.c contains the same assertions */
562+
assert(cf->ob2 == NULL);
563+
assert(cf->ob3 == NULL);
564+
}
565+
559566
f = cf->f_back;
567+
/* Set new exception for this thread.
568+
* This code is follows suit the code of set_exc_info() in ceval.c */
569+
tmp_type = ts->exc_type;
570+
tmp_value = ts->exc_value;
571+
tmp_tb = ts->exc_traceback;
560572
ts->exc_type = cf->ob1;
561573
ts->exc_value = cf->ob2;
562574
ts->exc_traceback = cf->ob3;
563575
cf->ob1 = cf->ob2 = cf->ob3 = NULL;
576+
577+
Py_XDECREF(tmp_type);
578+
Py_XDECREF(tmp_value);
579+
Py_XDECREF(tmp_tb);
580+
564581
Py_DECREF(cf);
565582
ts->frame = f;
566583
return STACKLESS_PACK(ts, retval);
@@ -1071,17 +1088,32 @@ slp_schedule_task_prepared(PyThreadState *ts, PyObject **result, PyTaskletObject
10711088
}
10721089
if (ts->exc_type != NULL) {
10731090
/* build a shadow frame if we are returning here*/
1091+
/* The following code follows suit the code of sys.exc_clear() and
1092+
* ceval.c set_exc_info()
1093+
*/
10741094
if (ts->frame != NULL) {
10751095
PyCFrameObject *f = slp_cframe_new(slp_restore_exception, 1);
10761096
if (f == NULL)
10771097
return -1;
10781098
f->ob1 = ts->exc_type;
10791099
f->ob2 = ts->exc_value;
10801100
f->ob3 = ts->exc_traceback;
1101+
ts->exc_type = NULL;
1102+
ts->exc_value = NULL;
1103+
ts->exc_traceback = NULL;
10811104
prev->f.frame = (PyFrameObject *) f;
1105+
} else {
1106+
PyObject *tmp_type, *tmp_value, *tmp_tb;
1107+
tmp_type = ts->exc_type;
1108+
tmp_value = ts->exc_value;
1109+
tmp_tb = ts->exc_traceback;
1110+
ts->exc_type = NULL;
1111+
ts->exc_value = NULL;
1112+
ts->exc_traceback = NULL;
1113+
Py_XDECREF(tmp_type);
1114+
Py_XDECREF(tmp_value);
1115+
Py_XDECREF(tmp_tb);
10821116
}
1083-
ts->exc_type = ts->exc_value =
1084-
ts->exc_traceback = NULL;
10851117
}
10861118
if (ts->use_tracing || ts->tracing) {
10871119
/* build a shadow frame if we are returning here */
@@ -1425,12 +1457,19 @@ slp_tasklet_end(PyObject *retval)
14251457
* clean up any current exception - this tasklet is dead.
14261458
* This only happens if we are killing tasklets in the middle
14271459
* of their execution.
1460+
* The code follows suit the code of sys.exc_clear().
14281461
*/
14291462
if (ts->exc_type != NULL && ts->exc_type != Py_None) {
1430-
Py_DECREF(ts->exc_type);
1431-
Py_XDECREF(ts->exc_value);
1432-
Py_XDECREF(ts->exc_traceback);
1433-
ts->exc_type = ts->exc_value = ts->exc_traceback = NULL;
1463+
PyObject *tmp_type, *tmp_value, *tmp_tb;
1464+
tmp_type = ts->exc_type;
1465+
tmp_value = ts->exc_value;
1466+
tmp_tb = ts->exc_traceback;
1467+
ts->exc_type = NULL;
1468+
ts->exc_value = NULL;
1469+
ts->exc_traceback = NULL;
1470+
Py_DECREF(tmp_type);
1471+
Py_XDECREF(tmp_value);
1472+
Py_XDECREF(tmp_tb);
14341473
}
14351474

14361475
/* capture all exceptions */

0 commit comments

Comments
 (0)