Skip to content

Commit 5a30620

Browse files
jdemeyervstinner
authored andcommitted
bpo-25750: Add test on bad descriptor __get__() (GH-9084)
1 parent b2e2025 commit 5a30620

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

@@ -4757,6 +4762,22 @@ def __call__(self, arg):
47574762
self.assertRegex(repr(method),
47584763
r"<bound method qualname of <object object at .*>>")
47594764

4765+
@unittest.skipIf(_testcapi is None, 'need the _testcapi module')
4766+
def test_bpo25750(self):
4767+
# bpo-25750: calling a descriptor (implemented as built-in
4768+
# function with METH_FASTCALL) should not crash CPython if the
4769+
# descriptor deletes itself from the class.
4770+
class Descr:
4771+
__get__ = _testcapi.bad_get
4772+
4773+
class X:
4774+
descr = Descr()
4775+
def __new__(cls):
4776+
cls.descr = None
4777+
# Create this large list to corrupt some unused memory
4778+
cls.lst = [2**i for i in range(10000)]
4779+
X.descr
4780+
47604781

47614782
class DictProxyTests(unittest.TestCase):
47624783
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 PyObject *
45544576
encode_locale_ex(PyObject *self, PyObject *args)
45554577
{
@@ -5017,6 +5039,7 @@ static PyMethodDef TestMethods[] = {
50175039
{"get_mapping_items", get_mapping_items, METH_O},
50185040
{"test_pythread_tss_key_state", test_pythread_tss_key_state, METH_VARARGS},
50195041
{"hamt", new_hamt, METH_NOARGS},
5042+
{"bad_get", bad_get, METH_FASTCALL},
50205043
{"EncodeLocaleEx", encode_locale_ex, METH_VARARGS},
50215044
{"DecodeLocaleEx", decode_locale_ex, METH_VARARGS},
50225045
{"get_coreconfig", get_coreconfig, METH_NOARGS},

0 commit comments

Comments
 (0)