diff --git a/Lib/test/test_capi.py b/Lib/test/test_capi.py index 795aa78d886..4dd78bb9a2f 100644 --- a/Lib/test/test_capi.py +++ b/Lib/test/test_capi.py @@ -184,6 +184,13 @@ class CAPITest(unittest.TestCase): o @= m1 self.assertEqual(o, ("matmul", 42, m1)) + def test_c_type_with_ipow(self): + # When the __ipow__ method of a type was implemented in C, using the + # modulo param would cause segfaults. + o = _testcapi.ipowType() + self.assertEqual(o.__ipow__(1), (1, None)) + self.assertEqual(o.__ipow__(2, 2), (2, 2)) + def test_return_null_without_error(self): # Issue #23571: A function must not return NULL without setting an # error diff --git a/Misc/NEWS.d/next/C API/2019-05-24-07-11-08.bpo-36379.8zgoKe.rst b/Misc/NEWS.d/next/C API/2019-05-24-07-11-08.bpo-36379.8zgoKe.rst new file mode 100644 index 00000000000..6a699b2084e --- /dev/null +++ b/Misc/NEWS.d/next/C API/2019-05-24-07-11-08.bpo-36379.8zgoKe.rst @@ -0,0 +1,2 @@ +Fix crashes when attempting to use the *modulo* parameter when ``__ipow__`` +is implemented in C. diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index ca6e87b79c4..b42f41cc8d8 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -5522,6 +5522,27 @@ static PyTypeObject matmulType = { PyObject_Del, /* tp_free */ }; +typedef struct { + PyObject_HEAD +} ipowObject; + +static PyObject * +ipowType_ipow(PyObject *self, PyObject *other, PyObject *mod) +{ + return Py_BuildValue("OO", other, mod); +} + +static PyNumberMethods ipowType_as_number = { + .nb_inplace_power = ipowType_ipow +}; + +static PyTypeObject ipowType = { + PyVarObject_HEAD_INIT(NULL, 0) + .tp_name = "ipowType", + .tp_basicsize = sizeof(ipowObject), + .tp_as_number = &ipowType_as_number, + .tp_new = PyType_GenericNew +}; typedef struct { PyObject_HEAD @@ -5947,6 +5968,11 @@ PyInit__testcapi(void) return NULL; Py_INCREF(&matmulType); PyModule_AddObject(m, "matmulType", (PyObject *)&matmulType); + if (PyType_Ready(&ipowType) < 0) { + return NULL; + } + Py_INCREF(&ipowType); + PyModule_AddObject(m, "ipowType", (PyObject *)&ipowType); if (PyType_Ready(&awaitType) < 0) return NULL; diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 64c2ceab557..b6d925c1442 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -7016,7 +7016,7 @@ static slotdef slotdefs[] = { IBSLOT("__imod__", nb_inplace_remainder, slot_nb_inplace_remainder, wrap_binaryfunc, "%="), IBSLOT("__ipow__", nb_inplace_power, slot_nb_inplace_power, - wrap_binaryfunc, "**="), + wrap_ternaryfunc, "**="), IBSLOT("__ilshift__", nb_inplace_lshift, slot_nb_inplace_lshift, wrap_binaryfunc, "<<="), IBSLOT("__irshift__", nb_inplace_rshift, slot_nb_inplace_rshift,