From 842acaab1376c5c84fd5966bb6070e289880e1ca Mon Sep 17 00:00:00 2001 From: Zackery Spytz Date: Mon, 17 Dec 2018 07:52:45 -0700 Subject: bpo-35504: Fix segfaults and SystemErrors when deleting certain attrs. (GH-11175) --- Lib/ctypes/test/test_strings.py | 7 +++++++ Lib/sqlite3/test/regression.py | 4 ++++ Lib/test/multibytecodec_support.py | 5 +++++ Lib/test/test_asyncio/test_futures.py | 7 +++++++ Lib/test/test_asyncio/test_tasks.py | 9 +++++++++ Lib/test/test_frame.py | 10 ++++++---- Lib/test/test_io.py | 5 +++++ .../2018-12-15-14-01-45.bpo-35504.JtKczP.rst | 2 ++ Modules/_asynciomodule.c | 12 ++++++++++++ Modules/_ctypes/_ctypes.c | 4 ++++ Modules/_io/textio.c | 4 ++++ Modules/_sqlite/connection.c | 4 ++++ Modules/_ssl.c | 4 ++++ Modules/cjkcodecs/multibytecodec.c | 4 ++++ Objects/frameobject.c | 4 ++++ 15 files changed, 81 insertions(+), 4 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2018-12-15-14-01-45.bpo-35504.JtKczP.rst diff --git a/Lib/ctypes/test/test_strings.py b/Lib/ctypes/test/test_strings.py index e28e141..5434efd 100644 --- a/Lib/ctypes/test/test_strings.py +++ b/Lib/ctypes/test/test_strings.py @@ -54,6 +54,13 @@ class StringArrayTestCase(unittest.TestCase): ## print BUF.from_param(c_char_p("python")) ## print BUF.from_param(BUF(*"pyth")) + def test_del_segfault(self): + BUF = c_char * 4 + buf = BUF() + with self.assertRaises(AttributeError): + del buf.raw + + @need_symbol('c_wchar') class WStringArrayTestCase(unittest.TestCase): def test(self): diff --git a/Lib/sqlite3/test/regression.py b/Lib/sqlite3/test/regression.py index 1c59a3c..865bd88 100644 --- a/Lib/sqlite3/test/regression.py +++ b/Lib/sqlite3/test/regression.py @@ -379,6 +379,10 @@ class RegressionTests(unittest.TestCase): del ref support.gc_collect() + def CheckDelIsolation_levelSegfault(self): + with self.assertRaises(AttributeError): + del self.con.isolation_level + class UnhashableFunc: __hash__ = None diff --git a/Lib/test/multibytecodec_support.py b/Lib/test/multibytecodec_support.py index 813b7aa..cca8af6 100644 --- a/Lib/test/multibytecodec_support.py +++ b/Lib/test/multibytecodec_support.py @@ -277,6 +277,11 @@ class TestBase: writer = self.writer(stream) writer.reset() + def test_incrementalencoder_del_segfault(self): + e = self.incrementalencoder() + with self.assertRaises(AttributeError): + del e.errors + class TestBase_Mapping(unittest.TestCase): pass_enctest = [] diff --git a/Lib/test/test_asyncio/test_futures.py b/Lib/test/test_asyncio/test_futures.py index 3339356..2e4583d 100644 --- a/Lib/test/test_asyncio/test_futures.py +++ b/Lib/test/test_asyncio/test_futures.py @@ -570,6 +570,13 @@ class CFutureTests(BaseFutureTests, test_utils.TestCase): except AttributeError: cls = None + def test_future_del_segfault(self): + fut = self._new_future(loop=self.loop) + with self.assertRaises(AttributeError): + del fut._asyncio_future_blocking + with self.assertRaises(AttributeError): + del fut._log_traceback + @unittest.skipUnless(hasattr(futures, '_CFuture'), 'requires the C _asyncio module') diff --git a/Lib/test/test_asyncio/test_tasks.py b/Lib/test/test_asyncio/test_tasks.py index c65d1f2..22f14f8 100644 --- a/Lib/test/test_asyncio/test_tasks.py +++ b/Lib/test/test_asyncio/test_tasks.py @@ -2546,6 +2546,15 @@ class CTask_CFuture_Tests(BaseTaskTests, SetMethodsTest, self.loop.run_until_complete(task) self.assertAlmostEqual(gettotalrefcount() - refs_before, 0, delta=10) + def test_del__log_destroy_pending_segfault(self): + @asyncio.coroutine + def coro(): + pass + task = self.new_task(self.loop, coro()) + self.loop.run_until_complete(task) + with self.assertRaises(AttributeError): + del task._log_destroy_pending + @unittest.skipUnless(hasattr(futures, '_CFuture') and hasattr(tasks, '_CTask'), diff --git a/Lib/test/test_frame.py b/Lib/test/test_frame.py index fd79508..d6aa283 100644 --- a/Lib/test/test_frame.py +++ b/Lib/test/test_frame.py @@ -109,10 +109,7 @@ class ClearTest(unittest.TestCase): self.assertIs(None, wr()) -class FrameLocalsTest(unittest.TestCase): - """ - Tests for the .f_locals attribute. - """ +class FrameAttrsTest(unittest.TestCase): def make_frames(self): def outer(): @@ -159,6 +156,11 @@ class FrameLocalsTest(unittest.TestCase): self.assertEqual(outer.f_locals, {}) self.assertEqual(inner.f_locals, {}) + def test_f_lineno_del_segfault(self): + f, _, _ = self.make_frames() + with self.assertRaises(AttributeError): + del f.f_lineno + class ReprTest(unittest.TestCase): """ diff --git a/Lib/test/test_io.py b/Lib/test/test_io.py index 14352ff..dc353c1 100644 --- a/Lib/test/test_io.py +++ b/Lib/test/test_io.py @@ -3663,6 +3663,11 @@ class CTextIOWrapperTest(TextIOWrapperTest): t2.buddy = t1 support.gc_collect() + def test_del__CHUNK_SIZE_SystemError(self): + t = self.TextIOWrapper(self.BytesIO(), encoding='ascii') + with self.assertRaises(AttributeError): + del t._CHUNK_SIZE + class PyTextIOWrapperTest(TextIOWrapperTest): io = pyio diff --git a/Misc/NEWS.d/next/Core and Builtins/2018-12-15-14-01-45.bpo-35504.JtKczP.rst b/Misc/NEWS.d/next/Core and Builtins/2018-12-15-14-01-45.bpo-35504.JtKczP.rst new file mode 100644 index 0000000..2a4f0f6 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2018-12-15-14-01-45.bpo-35504.JtKczP.rst @@ -0,0 +1,2 @@ +Fix segfaults and :exc:`SystemError`\ s when deleting certain attributes. +Patch by Zackery Spytz. diff --git a/Modules/_asynciomodule.c b/Modules/_asynciomodule.c index 0998cc1..7637cb7 100644 --- a/Modules/_asynciomodule.c +++ b/Modules/_asynciomodule.c @@ -1113,6 +1113,10 @@ FutureObj_set_blocking(FutureObj *fut, PyObject *val, void *Py_UNUSED(ignored)) if (future_ensure_alive(fut)) { return -1; } + if (val == NULL) { + PyErr_SetString(PyExc_AttributeError, "cannot delete attribute"); + return -1; + } int is_true = PyObject_IsTrue(val); if (is_true < 0) { @@ -1137,6 +1141,10 @@ FutureObj_get_log_traceback(FutureObj *fut, void *Py_UNUSED(ignored)) static int FutureObj_set_log_traceback(FutureObj *fut, PyObject *val, void *Py_UNUSED(ignored)) { + if (val == NULL) { + PyErr_SetString(PyExc_AttributeError, "cannot delete attribute"); + return -1; + } int is_true = PyObject_IsTrue(val); if (is_true < 0) { return -1; @@ -2015,6 +2023,10 @@ TaskObj_get_log_destroy_pending(TaskObj *task, void *Py_UNUSED(ignored)) static int TaskObj_set_log_destroy_pending(TaskObj *task, PyObject *val, void *Py_UNUSED(ignored)) { + if (val == NULL) { + PyErr_SetString(PyExc_AttributeError, "cannot delete attribute"); + return -1; + } int is_true = PyObject_IsTrue(val); if (is_true < 0) { return -1; diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c index 163b3e3..637be42 100644 --- a/Modules/_ctypes/_ctypes.c +++ b/Modules/_ctypes/_ctypes.c @@ -1191,6 +1191,10 @@ CharArray_set_raw(CDataObject *self, PyObject *value, void *Py_UNUSED(ignored)) Py_ssize_t size; Py_buffer view; + if (value == NULL) { + PyErr_SetString(PyExc_AttributeError, "cannot delete attribute"); + return -1; + } if (PyObject_GetBuffer(value, &view, PyBUF_SIMPLE) < 0) return -1; size = view.len; diff --git a/Modules/_io/textio.c b/Modules/_io/textio.c index 645d712..14f9488 100644 --- a/Modules/_io/textio.c +++ b/Modules/_io/textio.c @@ -3042,6 +3042,10 @@ textiowrapper_chunk_size_set(textio *self, PyObject *arg, void *context) { Py_ssize_t n; CHECK_ATTACHED_INT(self); + if (arg == NULL) { + PyErr_SetString(PyExc_AttributeError, "cannot delete attribute"); + return -1; + } n = PyNumber_AsSsize_t(arg, PyExc_ValueError); if (n == -1 && PyErr_Occurred()) return -1; diff --git a/Modules/_sqlite/connection.c b/Modules/_sqlite/connection.c index aab4b1a..e3340bf 100644 --- a/Modules/_sqlite/connection.c +++ b/Modules/_sqlite/connection.c @@ -1161,6 +1161,10 @@ static PyObject* pysqlite_connection_get_in_transaction(pysqlite_Connection* sel static int pysqlite_connection_set_isolation_level(pysqlite_Connection* self, PyObject* isolation_level, void *Py_UNUSED(ignored)) { + if (isolation_level == NULL) { + PyErr_SetString(PyExc_AttributeError, "cannot delete attribute"); + return -1; + } if (isolation_level == Py_None) { PyObject *res = pysqlite_connection_commit(self, NULL); if (!res) { diff --git a/Modules/_ssl.c b/Modules/_ssl.c index 269f003..4e3352d 100644 --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -3625,6 +3625,10 @@ static int set_post_handshake_auth(PySSLContext *self, PyObject *arg, void *c) { int (*verify_cb)(int, X509_STORE_CTX *) = NULL; int mode = SSL_CTX_get_verify_mode(self->ctx); + if (arg == NULL) { + PyErr_SetString(PyExc_AttributeError, "cannot delete attribute"); + return -1; + } int pha = PyObject_IsTrue(arg); if (pha == -1) { diff --git a/Modules/cjkcodecs/multibytecodec.c b/Modules/cjkcodecs/multibytecodec.c index 938a774..f266e5f 100644 --- a/Modules/cjkcodecs/multibytecodec.c +++ b/Modules/cjkcodecs/multibytecodec.c @@ -133,6 +133,10 @@ codecctx_errors_set(MultibyteStatefulCodecContext *self, PyObject *value, PyObject *cb; const char *str; + if (value == NULL) { + PyErr_SetString(PyExc_AttributeError, "cannot delete attribute"); + return -1; + } if (!PyUnicode_Check(value)) { PyErr_SetString(PyExc_TypeError, "errors must be a string"); return -1; diff --git a/Objects/frameobject.c b/Objects/frameobject.c index 400f99f..8488b96 100644 --- a/Objects/frameobject.c +++ b/Objects/frameobject.c @@ -105,6 +105,10 @@ frame_setlineno(PyFrameObject *f, PyObject* p_new_lineno, void *Py_UNUSED(ignore int blockstack[CO_MAXBLOCKS]; /* Walking the 'finally' blocks */ int blockstack_top = 0; /* (ditto) */ + if (p_new_lineno == NULL) { + PyErr_SetString(PyExc_AttributeError, "cannot delete attribute"); + return -1; + } /* f_lineno must be an integer. */ if (!PyLong_CheckExact(p_new_lineno)) { PyErr_SetString(PyExc_ValueError, -- cgit v0.12