Skip to content

Commit

Permalink
Issue python#115: fix an unlikely crash, if a context manager silence…
Browse files Browse the repository at this point in the history
…s 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
  • Loading branch information
Anselm Kruis committed Jan 5, 2017
1 parent 494f2c2 commit 9edb07b
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 16 deletions.
20 changes: 4 additions & 16 deletions Python/ceval.c
Original file line number Diff line number Diff line change
Expand Up @@ -1793,22 +1793,10 @@ slp_eval_frame_value(PyFrameObject *f, int throwflag, PyObject *retval)
err = 0;
Py_DECREF(retval);

if (err >= 0) {
if (err > 0) {
err = 0;
/* There was an exception and a true return */
v = SECOND();
w = THIRD();
STACKADJ(-2);
Py_INCREF(Py_None);
SET_TOP(Py_None);
Py_DECREF(u);
Py_DECREF(v);
Py_DECREF(w);
} else {
/* The stack was rearranged to remove EXIT
above. Let END_FINALLY do its thing */
}
if (err > 0) {
err = 0;
/* There was an exception and a True return */
PUSH(PyLong_FromLong((long) WHY_SILENCED));
}
/* XXX: The main loop contains a PREDICT(END_FINALLY).
* I wonder, if we must use it here?
Expand Down
4 changes: 4 additions & 0 deletions Stackless/changelog.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ What's New in Stackless 3.X.X?

*Release date: 20XX-XX-XX*

- https://bitbucket.org/stackless-dev/stackless/issues/115
Fix an unlikely crash caused by an context manager, which silences an
exception.

- https://bitbucket.org/stackless-dev/stackless/issues/117
Fix various reference leaks:
- Leak of a reference to Py_None in generator.throw()
Expand Down
37 changes: 37 additions & 0 deletions Stackless/unittests/test_defects.py
Original file line number Diff line number Diff line change
Expand Up @@ -492,6 +492,43 @@ def test_kill_during_cPickle_stack_switch(self):
raise (self.killed[0], self.killed[1], self.killed[2])
self.assertIsNone(self.killed)


class TestContextManager(StacklessTestCase):
def test_crash_on_WHY_SILENCED(self):
current_switch = stackless.current.switch
steps = []

class CtxManager:
def __enter__(self):
steps.append(2)

def __exit__(self, exc_type, exc_val, exc_tb):
steps.append(4)
current_switch() # causes a stack corruption upon resuming __exit__
steps.append(5)
return True # silence the exception

def task():
try:
steps.append(1)
return "OK"
finally:
with CtxManager():
steps.append(3)
1 // 0
steps.append(6)
# Stackless issue #115 ()
# Leaving this finally block crashes Python,
# because the interpreter stack is corrupt.

t = stackless.tasklet(task)()
t.run()
self.assertListEqual(steps, [1, 2, 3, 4])
t.run()
r = t.tempval
self.assertListEqual(steps, [1, 2, 3, 4, 5, 6])


if __name__ == '__main__':
if not sys.argv[1:]:
sys.argv.append('-v')
Expand Down

0 comments on commit 9edb07b

Please sign in to comment.