Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions Lib/test/test_descr.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@
from copy import deepcopy
from test import support

try:
import _testcapi
except ImportError:
_testcapi = None


class OperatorsTest(unittest.TestCase):

Expand Down Expand Up @@ -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')

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can wrap the test with @cpython_only.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wanted to propose the same change, but IMHO @unittest.skipIf(_testcapi is None, ...) is fine since _testcapi is specific to CPython and it's a common pattern.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cpython_only serves also documenting purpose. It is common to decorate all tests that use _testcapi with cpython_only.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jdemeyer: Would you mind to add @cpython_only? IMHO it's better to add it first, before "_testcapi is None".

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would you mind to add @cpython_only? IMHO it's better to add it first, before "_testcapi is None".

Do we really need both? Doesn't @cpython_only imply that _testcapi is available?

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):
Expand Down
23 changes: 23 additions & 0 deletions Modules/_testcapimodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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},
Expand Down