Skip to content

Commit 47a997b

Browse files
committed
bpo-25750: add testcase
1 parent 16e1807 commit 47a997b

File tree

2 files changed

+44
-0
lines changed

2 files changed

+44
-0
lines changed

Lib/test/test_descr.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,11 @@
1313
from copy import deepcopy
1414
from test import support
1515

16+
try:
17+
import _testcapi
18+
except ImportError:
19+
_testcapi = None
20+
1621

1722
class OperatorsTest(unittest.TestCase):
1823

@@ -4724,6 +4729,22 @@ def __call__(self, arg):
47244729
self.assertRegex(repr(method),
47254730
r"<bound method qualname of <object object at .*>>")
47264731

4732+
@unittest.skipIf(_testcapi is None, 'need the _testcapi module')
4733+
def test_bpo25750(self):
4734+
# bpo-25750: calling a descriptor (implemented as built-in
4735+
# function with METH_FASTCALL) should not crash CPython if the
4736+
# descriptor deletes itself from the class.
4737+
class Descr:
4738+
__get__ = _testcapi.bad_get
4739+
4740+
class X:
4741+
descr = Descr()
4742+
def __new__(cls):
4743+
cls.descr = None
4744+
# Create this large list to corrupt some unused memory
4745+
cls.lst = [2**i for i in range(10000)]
4746+
X.descr
4747+
47274748

47284749
class DictProxyTests(unittest.TestCase):
47294750
def setUp(self):

Modules/_testcapimodule.c

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4550,6 +4550,28 @@ new_hamt(PyObject *self, PyObject *args)
45504550
}
45514551

45524552

4553+
/* def bad_get(self, obj, cls):
4554+
cls()
4555+
return repr(self)
4556+
*/
4557+
static PyObject*
4558+
bad_get(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
4559+
{
4560+
if (nargs != 3) {
4561+
PyErr_SetString(PyExc_TypeError, "bad_get requires exactly 3 arguments");
4562+
return NULL;
4563+
}
4564+
4565+
PyObject *res = PyObject_CallObject(args[2], NULL);
4566+
if (res == NULL) {
4567+
return NULL;
4568+
}
4569+
Py_DECREF(res);
4570+
4571+
return PyObject_Repr(args[0]);
4572+
}
4573+
4574+
45534575
static PyMethodDef TestMethods[] = {
45544576
{"raise_exception", raise_exception, METH_VARARGS},
45554577
{"raise_memoryerror", raise_memoryerror, METH_NOARGS},
@@ -4771,6 +4793,7 @@ static PyMethodDef TestMethods[] = {
47714793
{"get_mapping_items", get_mapping_items, METH_O},
47724794
{"test_pythread_tss_key_state", test_pythread_tss_key_state, METH_VARARGS},
47734795
{"hamt", new_hamt, METH_NOARGS},
4796+
{"bad_get", bad_get, METH_FASTCALL},
47744797
{NULL, NULL} /* sentinel */
47754798
};
47764799

0 commit comments

Comments
 (0)