bpo-35504: Fix segfaults and SystemErrors when deleting certain attrs. (GH-11175)

(cherry picked from commit 842acaab13)

Co-authored-by: Zackery Spytz <zspytz@gmail.com>
This commit is contained in:
Miss Islington (bot) 2018-12-17 07:10:20 -08:00 committed by GitHub
parent c367d52a74
commit cb272843f2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 81 additions and 4 deletions

View File

@ -54,6 +54,13 @@ class StringArrayTestCase(unittest.TestCase):
## print BUF.from_param(c_char_p("python")) ## print BUF.from_param(c_char_p("python"))
## print BUF.from_param(BUF(*"pyth")) ## 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') @need_symbol('c_wchar')
class WStringArrayTestCase(unittest.TestCase): class WStringArrayTestCase(unittest.TestCase):
def test(self): def test(self):

View File

@ -379,6 +379,10 @@ class RegressionTests(unittest.TestCase):
del ref del ref
support.gc_collect() support.gc_collect()
def CheckDelIsolation_levelSegfault(self):
with self.assertRaises(AttributeError):
del self.con.isolation_level
class UnhashableFunc: class UnhashableFunc:
__hash__ = None __hash__ = None

View File

@ -277,6 +277,11 @@ class TestBase:
writer = self.writer(stream) writer = self.writer(stream)
writer.reset() writer.reset()
def test_incrementalencoder_del_segfault(self):
e = self.incrementalencoder()
with self.assertRaises(AttributeError):
del e.errors
class TestBase_Mapping(unittest.TestCase): class TestBase_Mapping(unittest.TestCase):
pass_enctest = [] pass_enctest = []

View File

@ -566,6 +566,13 @@ class CFutureTests(BaseFutureTests, test_utils.TestCase):
except AttributeError: except AttributeError:
cls = None 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'), @unittest.skipUnless(hasattr(futures, '_CFuture'),
'requires the C _asyncio module') 'requires the C _asyncio module')

View File

@ -2512,6 +2512,15 @@ class CTask_CFuture_Tests(BaseTaskTests, SetMethodsTest,
self.loop.run_until_complete(task) self.loop.run_until_complete(task)
self.assertAlmostEqual(gettotalrefcount() - refs_before, 0, delta=10) 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 @unittest.skipUnless(hasattr(futures, '_CFuture') and
hasattr(tasks, '_CTask'), hasattr(tasks, '_CTask'),

View File

@ -109,10 +109,7 @@ class ClearTest(unittest.TestCase):
self.assertIs(None, wr()) self.assertIs(None, wr())
class FrameLocalsTest(unittest.TestCase): class FrameAttrsTest(unittest.TestCase):
"""
Tests for the .f_locals attribute.
"""
def make_frames(self): def make_frames(self):
def outer(): def outer():
@ -159,6 +156,11 @@ class FrameLocalsTest(unittest.TestCase):
self.assertEqual(outer.f_locals, {}) self.assertEqual(outer.f_locals, {})
self.assertEqual(inner.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): class ReprTest(unittest.TestCase):
""" """

View File

@ -3635,6 +3635,11 @@ class CTextIOWrapperTest(TextIOWrapperTest):
t2.buddy = t1 t2.buddy = t1
support.gc_collect() 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): class PyTextIOWrapperTest(TextIOWrapperTest):
io = pyio io = pyio

View File

@ -0,0 +1,2 @@
Fix segfaults and :exc:`SystemError`\ s when deleting certain attributes.
Patch by Zackery Spytz.

View File

@ -1110,6 +1110,10 @@ FutureObj_set_blocking(FutureObj *fut, PyObject *val, void *Py_UNUSED(ignored))
if (future_ensure_alive(fut)) { if (future_ensure_alive(fut)) {
return -1; return -1;
} }
if (val == NULL) {
PyErr_SetString(PyExc_AttributeError, "cannot delete attribute");
return -1;
}
int is_true = PyObject_IsTrue(val); int is_true = PyObject_IsTrue(val);
if (is_true < 0) { if (is_true < 0) {
@ -1134,6 +1138,10 @@ FutureObj_get_log_traceback(FutureObj *fut, void *Py_UNUSED(ignored))
static int static int
FutureObj_set_log_traceback(FutureObj *fut, PyObject *val, void *Py_UNUSED(ignored)) 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); int is_true = PyObject_IsTrue(val);
if (is_true < 0) { if (is_true < 0) {
return -1; return -1;
@ -2008,6 +2016,10 @@ TaskObj_get_log_destroy_pending(TaskObj *task, void *Py_UNUSED(ignored))
static int static int
TaskObj_set_log_destroy_pending(TaskObj *task, PyObject *val, void *Py_UNUSED(ignored)) 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); int is_true = PyObject_IsTrue(val);
if (is_true < 0) { if (is_true < 0) {
return -1; return -1;

View File

@ -1171,6 +1171,10 @@ CharArray_set_raw(CDataObject *self, PyObject *value, void *Py_UNUSED(ignored))
Py_ssize_t size; Py_ssize_t size;
Py_buffer view; Py_buffer view;
if (value == NULL) {
PyErr_SetString(PyExc_AttributeError, "cannot delete attribute");
return -1;
}
if (PyObject_GetBuffer(value, &view, PyBUF_SIMPLE) < 0) if (PyObject_GetBuffer(value, &view, PyBUF_SIMPLE) < 0)
return -1; return -1;
size = view.len; size = view.len;

View File

@ -3049,6 +3049,10 @@ textiowrapper_chunk_size_set(textio *self, PyObject *arg, void *context)
{ {
Py_ssize_t n; Py_ssize_t n;
CHECK_ATTACHED_INT(self); CHECK_ATTACHED_INT(self);
if (arg == NULL) {
PyErr_SetString(PyExc_AttributeError, "cannot delete attribute");
return -1;
}
n = PyNumber_AsSsize_t(arg, PyExc_ValueError); n = PyNumber_AsSsize_t(arg, PyExc_ValueError);
if (n == -1 && PyErr_Occurred()) if (n == -1 && PyErr_Occurred())
return -1; return -1;

View File

@ -1138,6 +1138,10 @@ static PyObject* pysqlite_connection_get_in_transaction(pysqlite_Connection* sel
static int static int
pysqlite_connection_set_isolation_level(pysqlite_Connection* self, PyObject* isolation_level, void *Py_UNUSED(ignored)) 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) { if (isolation_level == Py_None) {
PyObject *res = pysqlite_connection_commit(self, NULL); PyObject *res = pysqlite_connection_commit(self, NULL);
if (!res) { if (!res) {

View File

@ -3626,6 +3626,10 @@ static int
set_post_handshake_auth(PySSLContext *self, PyObject *arg, void *c) { set_post_handshake_auth(PySSLContext *self, PyObject *arg, void *c) {
int (*verify_cb)(int, X509_STORE_CTX *) = NULL; int (*verify_cb)(int, X509_STORE_CTX *) = NULL;
int mode = SSL_CTX_get_verify_mode(self->ctx); 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); int pha = PyObject_IsTrue(arg);
if (pha == -1) { if (pha == -1) {

View File

@ -133,6 +133,10 @@ codecctx_errors_set(MultibyteStatefulCodecContext *self, PyObject *value,
PyObject *cb; PyObject *cb;
const char *str; const char *str;
if (value == NULL) {
PyErr_SetString(PyExc_AttributeError, "cannot delete attribute");
return -1;
}
if (!PyUnicode_Check(value)) { if (!PyUnicode_Check(value)) {
PyErr_SetString(PyExc_TypeError, "errors must be a string"); PyErr_SetString(PyExc_TypeError, "errors must be a string");
return -1; return -1;

View File

@ -90,6 +90,10 @@ frame_setlineno(PyFrameObject *f, PyObject* p_new_lineno, void *Py_UNUSED(ignore
int blockstack_top = 0; /* (ditto) */ int blockstack_top = 0; /* (ditto) */
unsigned char setup_op = 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. */ /* f_lineno must be an integer. */
if (!PyLong_CheckExact(p_new_lineno)) { if (!PyLong_CheckExact(p_new_lineno)) {
PyErr_SetString(PyExc_ValueError, PyErr_SetString(PyExc_ValueError,