[Python-checkins] bpo-25750: Add test on bad descriptor __get__() (GH-9084)

Victor Stinner webhook-mailer at python.org
Fri Oct 19 17:50:10 EDT 2018


https://github.com/python/cpython/commit/5a30620e68ebb911eef4d583de3776d782148637
commit: 5a30620e68ebb911eef4d583de3776d782148637
branch: master
author: jdemeyer <jdemeyer at cage.ugent.be>
committer: Victor Stinner <vstinner at redhat.com>
date: 2018-10-19T23:50:06+02:00
summary:

bpo-25750: Add test on bad descriptor __get__() (GH-9084)

files:
M Lib/test/test_descr.py
M Modules/_testcapimodule.c

diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py
index b96d35cc7299..b38cb765cdc0 100644
--- a/Lib/test/test_descr.py
+++ b/Lib/test/test_descr.py
@@ -13,6 +13,11 @@
 from copy import deepcopy
 from test import support
 
+try:
+    import _testcapi
+except ImportError:
+    _testcapi = None
+
 
 class OperatorsTest(unittest.TestCase):
 
@@ -4757,6 +4762,22 @@ def __call__(self, arg):
         self.assertRegex(repr(method),
             r"<bound method qualname of <object object at .*>>")
 
+    @unittest.skipIf(_testcapi is None, 'need the _testcapi module')
+    def test_bpo25750(self):
+        # bpo-25750: calling a descriptor (implemented as built-in
+        # function with METH_FASTCALL) should not crash CPython if the
+        # descriptor deletes itself from the class.
+        class Descr:
+            __get__ = _testcapi.bad_get
+
+        class X:
+            descr = Descr()
+            def __new__(cls):
+                cls.descr = None
+                # Create this large list to corrupt some unused memory
+                cls.lst = [2**i for i in range(10000)]
+        X.descr
+
 
 class DictProxyTests(unittest.TestCase):
     def setUp(self):
diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c
index add642f223af..4381e93ca913 100644
--- a/Modules/_testcapimodule.c
+++ b/Modules/_testcapimodule.c
@@ -4550,6 +4550,28 @@ new_hamt(PyObject *self, PyObject *args)
 }
 
 
+/* def bad_get(self, obj, cls):
+       cls()
+       return repr(self)
+*/
+static PyObject*
+bad_get(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
+{
+    if (nargs != 3) {
+        PyErr_SetString(PyExc_TypeError, "bad_get requires exactly 3 arguments");
+        return NULL;
+    }
+
+    PyObject *res = PyObject_CallObject(args[2], NULL);
+    if (res == NULL) {
+        return NULL;
+    }
+    Py_DECREF(res);
+
+    return PyObject_Repr(args[0]);
+}
+
+
 static PyObject *
 encode_locale_ex(PyObject *self, PyObject *args)
 {
@@ -5017,6 +5039,7 @@ static PyMethodDef TestMethods[] = {
     {"get_mapping_items", get_mapping_items, METH_O},
     {"test_pythread_tss_key_state", test_pythread_tss_key_state, METH_VARARGS},
     {"hamt", new_hamt, METH_NOARGS},
+    {"bad_get", bad_get, METH_FASTCALL},
     {"EncodeLocaleEx", encode_locale_ex, METH_VARARGS},
     {"DecodeLocaleEx", decode_locale_ex, METH_VARARGS},
     {"get_coreconfig", get_coreconfig, METH_NOARGS},



More information about the Python-checkins mailing list