[Python-checkins] bpo-36379: __ipow__ must be a ternaryfunc, not a binaryfunc (GH-13546)

Miss Islington (bot) webhook-mailer at python.org
Fri May 31 05:46:40 EDT 2019


https://github.com/python/cpython/commit/c7f803b08ed5211701c75f98ba9ada85d45ac155
commit: c7f803b08ed5211701c75f98ba9ada85d45ac155
branch: master
author: Zackery Spytz <zspytz at gmail.com>
committer: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com>
date: 2019-05-31T02:46:36-07:00
summary:

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

files:
A Misc/NEWS.d/next/C API/2019-05-24-07-11-08.bpo-36379.8zgoKe.rst
M Lib/test/test_capi.py
M Modules/_testcapimodule.c
M Objects/typeobject.c

diff --git a/Lib/test/test_capi.py b/Lib/test/test_capi.py
index 795aa78d8866..4dd78bb9a2fd 100644
--- a/Lib/test/test_capi.py
+++ b/Lib/test/test_capi.py
@@ -184,6 +184,13 @@ def test_c_type_with_matrix_multiplication(self):
         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 000000000000..6a699b2084e4
--- /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 ca6e87b79c47..b42f41cc8d8f 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 64c2ceab5573..b6d925c1442e 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,



More information about the Python-checkins mailing list