Skip to content

Commit c7f803b

Browse files
ZackerySpytzmiss-islington
authored andcommitted
bpo-36379: __ipow__ must be a ternaryfunc, not a binaryfunc (GH-13546)
If a type's __ipow__ method was implemented in C, attempting to use the *modulo* parameter would cause crashes. https://bugs.python.org/issue36379
1 parent c7f7069 commit c7f803b

File tree

4 files changed

+36
-1
lines changed

4 files changed

+36
-1
lines changed

Lib/test/test_capi.py

+7
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,13 @@ def test_c_type_with_matrix_multiplication(self):
184184
o @= m1
185185
self.assertEqual(o, ("matmul", 42, m1))
186186

187+
def test_c_type_with_ipow(self):
188+
# When the __ipow__ method of a type was implemented in C, using the
189+
# modulo param would cause segfaults.
190+
o = _testcapi.ipowType()
191+
self.assertEqual(o.__ipow__(1), (1, None))
192+
self.assertEqual(o.__ipow__(2, 2), (2, 2))
193+
187194
def test_return_null_without_error(self):
188195
# Issue #23571: A function must not return NULL without setting an
189196
# error
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix crashes when attempting to use the *modulo* parameter when ``__ipow__``
2+
is implemented in C.

Modules/_testcapimodule.c

+26
Original file line numberDiff line numberDiff line change
@@ -5522,6 +5522,27 @@ static PyTypeObject matmulType = {
55225522
PyObject_Del, /* tp_free */
55235523
};
55245524

5525+
typedef struct {
5526+
PyObject_HEAD
5527+
} ipowObject;
5528+
5529+
static PyObject *
5530+
ipowType_ipow(PyObject *self, PyObject *other, PyObject *mod)
5531+
{
5532+
return Py_BuildValue("OO", other, mod);
5533+
}
5534+
5535+
static PyNumberMethods ipowType_as_number = {
5536+
.nb_inplace_power = ipowType_ipow
5537+
};
5538+
5539+
static PyTypeObject ipowType = {
5540+
PyVarObject_HEAD_INIT(NULL, 0)
5541+
.tp_name = "ipowType",
5542+
.tp_basicsize = sizeof(ipowObject),
5543+
.tp_as_number = &ipowType_as_number,
5544+
.tp_new = PyType_GenericNew
5545+
};
55255546

55265547
typedef struct {
55275548
PyObject_HEAD
@@ -5947,6 +5968,11 @@ PyInit__testcapi(void)
59475968
return NULL;
59485969
Py_INCREF(&matmulType);
59495970
PyModule_AddObject(m, "matmulType", (PyObject *)&matmulType);
5971+
if (PyType_Ready(&ipowType) < 0) {
5972+
return NULL;
5973+
}
5974+
Py_INCREF(&ipowType);
5975+
PyModule_AddObject(m, "ipowType", (PyObject *)&ipowType);
59505976

59515977
if (PyType_Ready(&awaitType) < 0)
59525978
return NULL;

Objects/typeobject.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -7016,7 +7016,7 @@ static slotdef slotdefs[] = {
70167016
IBSLOT("__imod__", nb_inplace_remainder, slot_nb_inplace_remainder,
70177017
wrap_binaryfunc, "%="),
70187018
IBSLOT("__ipow__", nb_inplace_power, slot_nb_inplace_power,
7019-
wrap_binaryfunc, "**="),
7019+
wrap_ternaryfunc, "**="),
70207020
IBSLOT("__ilshift__", nb_inplace_lshift, slot_nb_inplace_lshift,
70217021
wrap_binaryfunc, "<<="),
70227022
IBSLOT("__irshift__", nb_inplace_rshift, slot_nb_inplace_rshift,

0 commit comments

Comments
 (0)