Commit 18f59691 authored by Serhiy Storchaka's avatar Serhiy Storchaka

Issue #21677: Fixed chaining nonnormalized exceptions in io close() methods.

parent 4d421742
...@@ -792,9 +792,27 @@ class CommonBufferedTests: ...@@ -792,9 +792,27 @@ class CommonBufferedTests:
with self.assertRaises(OSError) as err: # exception not swallowed with self.assertRaises(OSError) as err: # exception not swallowed
b.close() b.close()
self.assertEqual(err.exception.args, ('close',)) self.assertEqual(err.exception.args, ('close',))
self.assertIsInstance(err.exception.__context__, OSError)
self.assertEqual(err.exception.__context__.args, ('flush',)) self.assertEqual(err.exception.__context__.args, ('flush',))
self.assertFalse(b.closed) self.assertFalse(b.closed)
def test_nonnormalized_close_error_on_close(self):
# Issue #21677
raw = self.MockRawIO()
def bad_flush():
raise non_existing_flush
def bad_close():
raise non_existing_close
raw.close = bad_close
b = self.tp(raw)
b.flush = bad_flush
with self.assertRaises(NameError) as err: # exception not swallowed
b.close()
self.assertIn('non_existing_close', str(err.exception))
self.assertIsInstance(err.exception.__context__, NameError)
self.assertIn('non_existing_flush', str(err.exception.__context__))
self.assertFalse(b.closed)
def test_multi_close(self): def test_multi_close(self):
raw = self.MockRawIO() raw = self.MockRawIO()
b = self.tp(raw) b = self.tp(raw)
...@@ -2576,6 +2594,39 @@ class TextIOWrapperTest(unittest.TestCase): ...@@ -2576,6 +2594,39 @@ class TextIOWrapperTest(unittest.TestCase):
self.assertRaises(OSError, txt.close) # exception not swallowed self.assertRaises(OSError, txt.close) # exception not swallowed
self.assertTrue(txt.closed) self.assertTrue(txt.closed)
def test_close_error_on_close(self):
buffer = self.BytesIO(self.testdata)
def bad_flush():
raise OSError('flush')
def bad_close():
raise OSError('close')
buffer.close = bad_close
txt = self.TextIOWrapper(buffer, encoding="ascii")
txt.flush = bad_flush
with self.assertRaises(OSError) as err: # exception not swallowed
txt.close()
self.assertEqual(err.exception.args, ('close',))
self.assertIsInstance(err.exception.__context__, OSError)
self.assertEqual(err.exception.__context__.args, ('flush',))
self.assertFalse(txt.closed)
def test_nonnormalized_close_error_on_close(self):
# Issue #21677
buffer = self.BytesIO(self.testdata)
def bad_flush():
raise non_existing_flush
def bad_close():
raise non_existing_close
buffer.close = bad_close
txt = self.TextIOWrapper(buffer, encoding="ascii")
txt.flush = bad_flush
with self.assertRaises(NameError) as err: # exception not swallowed
txt.close()
self.assertIn('non_existing_close', str(err.exception))
self.assertIsInstance(err.exception.__context__, NameError)
self.assertIn('non_existing_flush', str(err.exception.__context__))
self.assertFalse(txt.closed)
def test_multi_close(self): def test_multi_close(self):
txt = self.TextIOWrapper(self.BytesIO(self.testdata), encoding="ascii") txt = self.TextIOWrapper(self.BytesIO(self.testdata), encoding="ascii")
txt.close() txt.close()
......
...@@ -22,6 +22,8 @@ Core and Builtins ...@@ -22,6 +22,8 @@ Core and Builtins
Library Library
------- -------
- Issue #21677: Fixed chaining nonnormalized exceptions in io close() methods.
- Issue #11709: Fix the pydoc.help function to not fail when sys.stdin is not a - Issue #11709: Fix the pydoc.help function to not fail when sys.stdin is not a
valid file. valid file.
......
...@@ -549,6 +549,7 @@ buffered_close(buffered *self, PyObject *args) ...@@ -549,6 +549,7 @@ buffered_close(buffered *self, PyObject *args)
} }
else { else {
PyObject *val2; PyObject *val2;
PyErr_NormalizeException(&exc, &val, &tb);
Py_DECREF(exc); Py_DECREF(exc);
Py_XDECREF(tb); Py_XDECREF(tb);
PyErr_Fetch(&exc, &val2, &tb); PyErr_Fetch(&exc, &val2, &tb);
......
...@@ -2614,6 +2614,7 @@ textiowrapper_close(textio *self, PyObject *args) ...@@ -2614,6 +2614,7 @@ textiowrapper_close(textio *self, PyObject *args)
} }
else { else {
PyObject *val2; PyObject *val2;
PyErr_NormalizeException(&exc, &val, &tb);
Py_DECREF(exc); Py_DECREF(exc);
Py_XDECREF(tb); Py_XDECREF(tb);
PyErr_Fetch(&exc, &val2, &tb); PyErr_Fetch(&exc, &val2, &tb);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment