From 77b83ea4f837bf30b42566c59de6181e16d59c45 Mon Sep 17 00:00:00 2001 From: Aviv Palivoda Date: Fri, 6 Mar 2020 10:45:19 +0200 Subject: [PATCH] Separate coro exception stack --- Lib/test/test_exceptions.py | 15 ------------- vm/src/obj/objcoroinner.rs | 45 ++++++++++++++++++++++++++++--------- 2 files changed, 34 insertions(+), 26 deletions(-) diff --git a/Lib/test/test_exceptions.py b/Lib/test/test_exceptions.py index 746794ce6..ffb48abf9 100644 --- a/Lib/test/test_exceptions.py +++ b/Lib/test/test_exceptions.py @@ -716,8 +716,6 @@ class ExceptionTests(unittest.TestCase): print_error() # implicit "del e" here - # TODO: RUSTPYTHON - @unittest.expectedFailure def test_generator_leaking(self): # Test that generator exception state doesn't leak into the calling # frame @@ -748,8 +746,6 @@ class ExceptionTests(unittest.TestCase): del g self.assertEqual(sys.exc_info()[0], TypeError) - # TODO: RUSTPYTHON - @unittest.expectedFailure def test_generator_leaking2(self): # See issue 12475. def g(): @@ -765,8 +761,6 @@ class ExceptionTests(unittest.TestCase): pass self.assertEqual(sys.exc_info(), (None, None, None)) - # TODO: RUSTPYTHON - @unittest.expectedFailure def test_generator_leaking3(self): # See issue #23353. When gen.throw() is called, the caller's # exception state should be save and restored. @@ -786,7 +780,6 @@ class ExceptionTests(unittest.TestCase): self.assertIs(gen_exc, e) self.assertEqual(sys.exc_info(), (None, None, None)) - @unittest.skip("TODO: RUSTPYTHON") def test_generator_leaking4(self): # See issue #23353. When an exception is raised by a generator, # the caller's exception state should still be restored. @@ -814,8 +807,6 @@ class ExceptionTests(unittest.TestCase): # We used to find TypeError here. self.assertEqual(sys.exc_info(), (None, None, None)) - # TODO: RUSTPYTHON - @unittest.expectedFailure def test_generator_doesnt_retain_old_exc(self): def g(): self.assertIsInstance(sys.exc_info()[1], RuntimeError) @@ -828,8 +819,6 @@ class ExceptionTests(unittest.TestCase): next(it) self.assertRaises(StopIteration, next, it) - # TODO: RUSTPYTHON - @unittest.expectedFailure def test_generator_finalizing_and_exc_info(self): # See #7173 def simple_gen(): @@ -881,8 +870,6 @@ class ExceptionTests(unittest.TestCase): g.close() self._check_generator_cleanup_exc_state(do_close) - # TODO: RUSTPYTHON - @unittest.expectedFailure def test_generator_del_cleanup_exc_state(self): def do_del(g): g = None @@ -1303,8 +1290,6 @@ class ExceptionTests(unittest.TestCase): with self.assertRaises(MainError): coro.throw(SubError()) - # TODO: RUSTPYTHON - @unittest.expectedFailure def test_generator_doesnt_retain_old_exc2(self): #Issue 28884#msg282532 def g(): diff --git a/vm/src/obj/objcoroinner.rs b/vm/src/obj/objcoroinner.rs index e544e96fe..d5e9daad6 100644 --- a/vm/src/obj/objcoroinner.rs +++ b/vm/src/obj/objcoroinner.rs @@ -4,13 +4,14 @@ use crate::frame::{ExecutionResult, FrameRef}; use crate::pyobject::{PyObjectRef, PyResult}; use crate::vm::VirtualMachine; -use std::cell::Cell; +use std::cell::{Cell, RefCell}; #[derive(Debug)] pub struct Coro { frame: FrameRef, closed: Cell, running: Cell, + exceptions: RefCell>, } impl Coro { @@ -19,6 +20,7 @@ impl Coro { frame, closed: Cell::new(false), running: Cell::new(false), + exceptions: RefCell::new(vec![]), } } @@ -29,15 +31,32 @@ impl Coro { } } + fn run_with_context(&self, func: F, vm: &VirtualMachine) -> PyResult + where + F: FnOnce() -> PyResult, + { + self.running.set(true); + let curr_exception_stack_len = vm.exceptions.borrow().len(); + vm.exceptions + .borrow_mut() + .append(&mut self.exceptions.borrow_mut()); + let result = func(); + self.exceptions.replace( + vm.exceptions + .borrow_mut() + .split_off(curr_exception_stack_len), + ); + self.running.set(false); + result + } + pub fn send(&self, value: PyObjectRef, vm: &VirtualMachine) -> PyResult { if self.closed.get() { return Err(objiter::new_stop_iteration(vm)); } self.frame.push_value(value.clone()); - self.running.set(true); - let result = vm.run_frame(self.frame.clone()); - self.running.set(false); + let result = self.run_with_context(|| vm.run_frame(self.frame.clone()), vm); self.maybe_close(&result); result?.into_result(vm) } @@ -53,9 +72,9 @@ impl Coro { return Err(exceptions::normalize(exc_type, exc_val, exc_tb, vm)?); } vm.frames.borrow_mut().push(self.frame.clone()); + let result = + self.run_with_context(|| self.frame.gen_throw(vm, exc_type, exc_val, exc_tb), vm); self.running.set(true); - let result = self.frame.gen_throw(vm, exc_type, exc_val, exc_tb); - self.running.set(false); self.maybe_close(&result); vm.frames.borrow_mut().pop(); result?.into_result(vm) @@ -67,13 +86,17 @@ impl Coro { } vm.frames.borrow_mut().push(self.frame.clone()); self.running.set(true); - let result = self.frame.gen_throw( + let result = self.run_with_context( + || { + self.frame.gen_throw( + vm, + vm.ctx.exceptions.generator_exit.clone().into_object(), + vm.get_none(), + vm.get_none(), + ) + }, vm, - vm.ctx.exceptions.generator_exit.clone().into_object(), - vm.get_none(), - vm.get_none(), ); - self.running.set(false); vm.frames.borrow_mut().pop(); self.closed.set(true); match result {