Visitar URL original
Issue #115: fix an unlikely crash, if a context manager silences an e… · akruis/cpython@9edb07b · GitHub
Skip to content

Commit 9edb07b

Browse files
author
Anselm Kruis
committed
Issue python#115: fix an unlikely crash, if a context manager silences an exception
If Stackless calls the method __exit__() of a context manager with an exception and if the method first soft switches to another tasklet and then returns True, the interpreter stack gets corrupted. Fortunately most of the time nothing bad happens. https://bitbucket.org/stackless-dev/stackless/issues/115
1 parent 494f2c2 commit 9edb07b

3 files changed

Lines changed: 45 additions & 16 deletions

File tree

‎Python/ceval.c‎

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1793,22 +1793,10 @@ slp_eval_frame_value(PyFrameObject *f, int throwflag, PyObject *retval)
17931793
err = 0;
17941794
Py_DECREF(retval);
17951795

1796-
if (err >= 0) {
1797-
if (err > 0) {
1798-
err = 0;
1799-
/* There was an exception and a true return */
1800-
v = SECOND();
1801-
w = THIRD();
1802-
STACKADJ(-2);
1803-
Py_INCREF(Py_None);
1804-
SET_TOP(Py_None);
1805-
Py_DECREF(u);
1806-
Py_DECREF(v);
1807-
Py_DECREF(w);
1808-
} else {
1809-
/* The stack was rearranged to remove EXIT
1810-
above. Let END_FINALLY do its thing */
1811-
}
1796+
if (err > 0) {
1797+
err = 0;
1798+
/* There was an exception and a True return */
1799+
PUSH(PyLong_FromLong((long) WHY_SILENCED));
18121800
}
18131801
/* XXX: The main loop contains a PREDICT(END_FINALLY).
18141802
* I wonder, if we must use it here?

‎Stackless/changelog.txt‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ What's New in Stackless 3.X.X?
99

1010
*Release date: 20XX-XX-XX*
1111

12+
- https://bitbucket.org/stackless-dev/stackless/issues/115
13+
Fix an unlikely crash caused by an context manager, which silences an
14+
exception.
15+
1216
- https://bitbucket.org/stackless-dev/stackless/issues/117
1317
Fix various reference leaks:
1418
- Leak of a reference to Py_None in generator.throw()

‎Stackless/unittests/test_defects.py‎

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -492,6 +492,43 @@ def test_kill_during_cPickle_stack_switch(self):
492492
raise (self.killed[0], self.killed[1], self.killed[2])
493493
self.assertIsNone(self.killed)
494494

495+
496+
class TestContextManager(StacklessTestCase):
497+
def test_crash_on_WHY_SILENCED(self):
498+
current_switch = stackless.current.switch
499+
steps = []
500+
501+
class CtxManager:
502+
def __enter__(self):
503+
steps.append(2)
504+
505+
def __exit__(self, exc_type, exc_val, exc_tb):
506+
steps.append(4)
507+
current_switch() # causes a stack corruption upon resuming __exit__
508+
steps.append(5)
509+
return True # silence the exception
510+
511+
def task():
512+
try:
513+
steps.append(1)
514+
return "OK"
515+
finally:
516+
with CtxManager():
517+
steps.append(3)
518+
1 // 0
519+
steps.append(6)
520+
# Stackless issue #115 ()
521+
# Leaving this finally block crashes Python,
522+
# because the interpreter stack is corrupt.
523+
524+
t = stackless.tasklet(task)()
525+
t.run()
526+
self.assertListEqual(steps, [1, 2, 3, 4])
527+
t.run()
528+
r = t.tempval
529+
self.assertListEqual(steps, [1, 2, 3, 4, 5, 6])
530+
531+
495532
if __name__ == '__main__':
496533
if not sys.argv[1:]:
497534
sys.argv.append('-v')

0 commit comments

Comments
 (0)