diff --git a/Lib/ctypes/test/test_strings.py b/Lib/ctypes/test/test_strings.py index e28e141394d..5434efda10c 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 1c59a3cd31c..865bd88f74f 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 813b7aa1bd2..cca8af67d6d 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 8c837ad6b62..9608a3a81cc 100644 --- a/Lib/test/test_asyncio/test_futures.py +++ b/Lib/test/test_asyncio/test_futures.py @@ -566,6 +566,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 12c6ef4f619..d92ed32bc99 100644 --- a/Lib/test/test_asyncio/test_tasks.py +++ b/Lib/test/test_asyncio/test_tasks.py @@ -2512,6 +2512,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 fd795085a5c..d6aa2834cbc 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 b41141e28ad..4c206d287f2 100644 --- a/Lib/test/test_io.py +++ b/Lib/test/test_io.py @@ -3635,6 +3635,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 00000000000..2a4f0f694fe --- /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 5816a6748f6..35264f5815c 100644 --- a/Modules/_asynciomodule.c +++ b/Modules/_asynciomodule.c @@ -1110,6 +1110,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) { @@ -1134,6 +1138,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; @@ -2008,6 +2016,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 c5fc811ad98..937375a4ea4 100644 --- a/Modules/_ctypes/_ctypes.c +++ b/Modules/_ctypes/_ctypes.c @@ -1171,6 +1171,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 9d0d9cac40d..49b545c4787 100644 --- a/Modules/_io/textio.c +++ b/Modules/_io/textio.c @@ -3049,6 +3049,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 351317e78db..d43286a2d34 100644 --- a/Modules/_sqlite/connection.c +++ b/Modules/_sqlite/connection.c @@ -1138,6 +1138,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 310b38bf11f..9894ad821d6 100644 --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -3626,6 +3626,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 4d0aaf3a336..5c91ada103d 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 4ef10d0eb7b..4362615cb08 100644 --- a/Objects/frameobject.c +++ b/Objects/frameobject.c @@ -90,6 +90,10 @@ frame_setlineno(PyFrameObject *f, PyObject* p_new_lineno, void *Py_UNUSED(ignore int blockstack_top = 0; /* (ditto) */ unsigned char setup_op = 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,