]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
bpo-46323: Reduce stack usage of ctypes python callback function. (GH-31224)
authorDong-hee Na <donghee.na@python.org>
Wed, 9 Feb 2022 18:10:11 +0000 (03:10 +0900)
committerGitHub <noreply@github.com>
Wed, 9 Feb 2022 18:10:11 +0000 (03:10 +0900)
Misc/NEWS.d/next/Core and Builtins/2022-02-10-02-29-12.bpo-46323.HK_cs0.rst [new file with mode: 0644]
Modules/_ctypes/callbacks.c
Modules/_ctypes/callproc.c

diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-02-10-02-29-12.bpo-46323.HK_cs0.rst b/Misc/NEWS.d/next/Core and Builtins/2022-02-10-02-29-12.bpo-46323.HK_cs0.rst
new file mode 100644 (file)
index 0000000..16db7c5
--- /dev/null
@@ -0,0 +1,3 @@
+:mod:`ctypes` now allocates memory on the stack instead of on the heap
+to pass arguments while calling a Python callback function.
+Patch by Dong-hee Na.
index f2d9a530e6e38b2a33a1c0bb27eadeefe16548b8..591b944d76fcbef77a34646f1fc05ede1dfc345e 100644 (file)
 
 #include <stdbool.h>
 
+#ifdef MS_WIN32
+#  include <malloc.h>
+#endif
+
 #include <ffi.h>
 #include "ctypes.h"
 
+#ifdef HAVE_ALLOCA_H
+/* AIX needs alloca.h for alloca() */
+#include <alloca.h>
+#endif
+
 /**************************************************************/
 
 static void
@@ -148,7 +157,6 @@ static void _CallPythonObject(void *mem,
                               void **pArgs)
 {
     PyObject *result = NULL;
-    PyObject **args = NULL;
     Py_ssize_t i = 0, j = 0, nargs = 0;
     PyObject *error_object = NULL;
     int *space;
@@ -156,24 +164,10 @@ static void _CallPythonObject(void *mem,
 
     assert(PyTuple_Check(converters));
     nargs = PyTuple_GET_SIZE(converters);
-    /* Hm. What to return in case of error?
-       For COM, 0xFFFFFFFF seems better than 0.
-    */
-    if (nargs < 0) {
-        PrintError("BUG: PySequence_Length");
-        goto Done;
-    }
-
-    PyObject *args_stack[CTYPES_MAX_ARGCOUNT];
-    if (nargs <= CTYPES_MAX_ARGCOUNT) {
-        args = args_stack;
-    }
-    else {
-        args = PyMem_Malloc(nargs * sizeof(PyObject *));
-        if (args == NULL) {
-            PyErr_NoMemory();
-            goto Done;
-        }
+    assert(nargs <= CTYPES_MAX_ARGCOUNT);
+    PyObject **args = NULL;
+    if (nargs > 0) {
+        args = alloca(nargs * sizeof(PyObject *));
     }
 
     PyObject **cnvs = PySequence_Fast_ITEMS(converters);
@@ -310,9 +304,6 @@ static void _CallPythonObject(void *mem,
     for (j = 0; j < i; j++) {
         Py_DECREF(args[j]);
     }
-    if (args != args_stack) {
-        PyMem_Free(args);
-    }
     PyGILState_Release(state);
 }
 
index 6dba0ffaa515946c518c78ed49b68bbf7385b211..4a6b8ec3ee016f202de3cce8316beada4a629615 100644 (file)
@@ -1162,11 +1162,7 @@ PyObject *_ctypes_callproc(PPROC pProc,
         return NULL;
     }
 
-    args = (struct argument *)alloca(sizeof(struct argument) * argcount);
-    if (!args) {
-        PyErr_NoMemory();
-        return NULL;
-    }
+    args = alloca(sizeof(struct argument) * argcount);
     memset(args, 0, sizeof(struct argument) * argcount);
     argtype_count = argtypes ? PyTuple_GET_SIZE(argtypes) : 0;
 #ifdef MS_WIN32