https://github.com/python/cpython/commit/379352620ce4d77f7248939a4cf211db48fdd241
commit: 379352620ce4d77f7248939a4cf211db48fdd241
branch: main
author: Bénédikt Tran <10796600+picn...@users.noreply.github.com>
committer: picnixz <10796600+picn...@users.noreply.github.com>
date: 2025-04-18T12:24:34+02:00
summary:

gh-132097: use a macro for semantically casting function pointers (#132406)

files:
M Include/internal/pycore_emscripten_trampoline.h
M Include/methodobject.h
M Include/pyport.h
M Objects/descrobject.c
M Objects/methodobject.c
M Objects/typeobject.c
M Python/bytecodes.c
M Python/executor_cases.c.h
M Python/generated_cases.c.h

diff --git a/Include/internal/pycore_emscripten_trampoline.h 
b/Include/internal/pycore_emscripten_trampoline.h
index 7946eb5a74e974..16916f1a8eb16c 100644
--- a/Include/internal/pycore_emscripten_trampoline.h
+++ b/Include/internal/pycore_emscripten_trampoline.h
@@ -37,17 +37,18 @@ _PyEM_TrampolineCall(PyCFunctionWithKeywords func,
                      PyObject* kw);
 
 #define _PyCFunction_TrampolineCall(meth, self, args) \
-    _PyEM_TrampolineCall( \
-        (*(PyCFunctionWithKeywords)(void(*)(void))(meth)), (self), (args), 
NULL)
+    _PyEM_TrampolineCall(*_PyCFunctionWithKeywords_CAST(meth), (self), (args), 
NULL)
 
 #define _PyCFunctionWithKeywords_TrampolineCall(meth, self, args, kw) \
     _PyEM_TrampolineCall((meth), (self), (args), (kw))
 
-#define descr_set_trampoline_call(set, obj, value, closure) \
-    ((int)_PyEM_TrampolineCall((PyCFunctionWithKeywords)(set), (obj), (value), 
(PyObject*)(closure)))
+#define descr_set_trampoline_call(set, obj, value, closure)                 \
+    ((int)_PyEM_TrampolineCall(_PyCFunctionWithKeywords_CAST(set), (obj),   \
+                               (value), (PyObject*)(closure)))
 
-#define descr_get_trampoline_call(get, obj, closure) \
-    _PyEM_TrampolineCall((PyCFunctionWithKeywords)(get), (obj), 
(PyObject*)(closure), NULL)
+#define descr_get_trampoline_call(get, obj, closure)                \
+    _PyEM_TrampolineCall(_PyCFunctionWithKeywords_CAST(get), (obj), \
+                         (PyObject*)(closure), NULL)
 
 
 #else // defined(__EMSCRIPTEN__) && defined(PY_CALL_TRAMPOLINE)
diff --git a/Include/methodobject.h b/Include/methodobject.h
index cfff05f803309e..e6ec6421d1e59d 100644
--- a/Include/methodobject.h
+++ b/Include/methodobject.h
@@ -33,7 +33,7 @@ typedef PyObject *(*PyCMethod)(PyObject *, PyTypeObject *, 
PyObject *const *,
 typedef PyCFunctionFast _PyCFunctionFast;
 typedef PyCFunctionFastWithKeywords _PyCFunctionFastWithKeywords;
 
-// Cast an function to the PyCFunction type to use it with PyMethodDef.
+// Cast a function to the PyCFunction type to use it with PyMethodDef.
 //
 // This macro can be used to prevent compiler warnings if the first parameter
 // uses a different pointer type than PyObject* (ex: METH_VARARGS and METH_O
@@ -49,8 +49,17 @@ typedef PyCFunctionFastWithKeywords 
_PyCFunctionFastWithKeywords;
 // used to prevent a compiler warning. If the function has a single parameter,
 // it triggers an undefined behavior when Python calls it with 2 parameters
 // (bpo-33012).
-#define _PyCFunction_CAST(func) \
-    _Py_CAST(PyCFunction, _Py_CAST(void(*)(void), (func)))
+#define _PyCFunction_CAST(func)                         \
+    _Py_FUNC_CAST(PyCFunction, func)
+// The macros below are given for semantic convenience, allowing users
+// to see whether a cast to suppress an undefined behavior is necessary.
+// Note: At runtime, the original function signature must be respected.
+#define _PyCFunctionFast_CAST(func)                     \
+    _Py_FUNC_CAST(PyCFunctionFast, func)
+#define _PyCFunctionWithKeywords_CAST(func)             \
+    _Py_FUNC_CAST(PyCFunctionWithKeywords, func)
+#define _PyCFunctionFastWithKeywords_CAST(func)         \
+    _Py_FUNC_CAST(PyCFunctionFastWithKeywords, func)
 
 PyAPI_FUNC(PyCFunction) PyCFunction_GetFunction(PyObject *);
 PyAPI_FUNC(PyObject *) PyCFunction_GetSelf(PyObject *);
diff --git a/Include/pyport.h b/Include/pyport.h
index 2a7192c2c55cdd..ebce31f1d14a01 100644
--- a/Include/pyport.h
+++ b/Include/pyport.h
@@ -36,6 +36,16 @@
 // Macro to use the more powerful/dangerous C-style cast even in C++.
 #define _Py_CAST(type, expr) ((type)(expr))
 
+// Cast a function to another function type T.
+//
+// The macro first casts the function to the "void func(void)" type
+// to prevent compiler warnings.
+//
+// Note that using this cast only prevents the compiler from emitting
+// warnings, but does not prevent an undefined behavior at runtime if
+// the original function signature is not respected.
+#define _Py_FUNC_CAST(T, func) _Py_CAST(T, _Py_CAST(void(*)(void), (func)))
+
 // Static inline functions should use _Py_NULL rather than using directly NULL
 // to prevent C++ compiler warnings. On C23 and newer and on C++11 and newer,
 // _Py_NULL is defined as nullptr.
diff --git a/Objects/descrobject.c b/Objects/descrobject.c
index 451e07f58e161e..268af0b217cd98 100644
--- a/Objects/descrobject.c
+++ b/Objects/descrobject.c
@@ -519,7 +519,7 @@ wrapperdescr_raw_call(PyWrapperDescrObject *descr, PyObject 
*self,
     wrapperfunc wrapper = descr->d_base->wrapper;
 
     if (descr->d_base->flags & PyWrapperFlag_KEYWORDS) {
-        wrapperfunc_kwds wk = (wrapperfunc_kwds)(void(*)(void))wrapper;
+        wrapperfunc_kwds wk = _Py_FUNC_CAST(wrapperfunc_kwds, wrapper);
         return (*wk)(self, args, descr->d_wrapped, kwds);
     }
 
diff --git a/Objects/methodobject.c b/Objects/methodobject.c
index 189b026ab33559..8b28662631b227 100644
--- a/Objects/methodobject.c
+++ b/Objects/methodobject.c
@@ -567,7 +567,7 @@ cfunction_call(PyObject *func, PyObject *args, PyObject 
*kwargs)
     PyObject *result;
     if (flags & METH_KEYWORDS) {
         result = _PyCFunctionWithKeywords_TrampolineCall(
-            (*(PyCFunctionWithKeywords)(void(*)(void))meth),
+            *_PyCFunctionWithKeywords_CAST(meth),
             self, args, kwargs);
     }
     else {
diff --git a/Objects/typeobject.c b/Objects/typeobject.c
index 982f41fd47f92c..5663aee3c2e069 100644
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -10807,7 +10807,8 @@ static pytype_slotdef slotdefs[] = {
            "__repr__($self, /)\n--\n\nReturn repr(self)."),
     TPSLOT(__hash__, tp_hash, slot_tp_hash, wrap_hashfunc,
            "__hash__($self, /)\n--\n\nReturn hash(self)."),
-    FLSLOT(__call__, tp_call, slot_tp_call, 
(wrapperfunc)(void(*)(void))wrap_call,
+    FLSLOT(__call__, tp_call, slot_tp_call,
+           _Py_FUNC_CAST(wrapperfunc, wrap_call),
            "__call__($self, /, *args, **kwargs)\n--\n\nCall self as a 
function.",
            PyWrapperFlag_KEYWORDS),
     TPSLOT(__str__, tp_str, slot_tp_str, wrap_unaryfunc,
@@ -10844,7 +10845,8 @@ static pytype_slotdef slotdefs[] = {
     TPSLOT(__delete__, tp_descr_set, slot_tp_descr_set,
            wrap_descr_delete,
            "__delete__($self, instance, /)\n--\n\nDelete an attribute of 
instance."),
-    FLSLOT(__init__, tp_init, slot_tp_init, 
(wrapperfunc)(void(*)(void))wrap_init,
+    FLSLOT(__init__, tp_init, slot_tp_init,
+           _Py_FUNC_CAST(wrapperfunc, wrap_init),
            "__init__($self, /, *args, **kwargs)\n--\n\n"
            "Initialize self.  See help(type(self)) for accurate signature.",
            PyWrapperFlag_KEYWORDS),
diff --git a/Python/bytecodes.c b/Python/bytecodes.c
index 95786c91371e98..8aa41c2e412932 100644
--- a/Python/bytecodes.c
+++ b/Python/bytecodes.c
@@ -4170,7 +4170,7 @@ dummy_func(
                 DECREF_INPUTS();
                 ERROR_IF(true, error);
             }
-            PyObject *res_o = ((PyCFunctionFast)(void(*)(void))cfunc)(
+            PyObject *res_o = _PyCFunctionFast_CAST(cfunc)(
                 PyCFunction_GET_SELF(callable_o),
                 args_o,
                 total_args);
@@ -4202,8 +4202,7 @@ dummy_func(
             STAT_INC(CALL, hit);
             /* res = func(self, arguments, nargs, kwnames) */
             PyCFunctionFastWithKeywords cfunc =
-                (PyCFunctionFastWithKeywords)(void(*)(void))
-                PyCFunction_GET_FUNCTION(callable_o);
+                
_PyCFunctionFastWithKeywords_CAST(PyCFunction_GET_FUNCTION(callable_o));
 
             STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o);
             if (CONVERSION_FAILED(args_o)) {
@@ -4371,7 +4370,7 @@ dummy_func(
                 ERROR_IF(true, error);
             }
             PyCFunctionFastWithKeywords cfunc =
-                (PyCFunctionFastWithKeywords)(void(*)(void))meth->ml_meth;
+                _PyCFunctionFastWithKeywords_CAST(meth->ml_meth);
             PyObject *res_o = cfunc(self, (args_o + 1), nargs, NULL);
             STACKREFS_TO_PYOBJECTS_CLEANUP(args_o);
             assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL));
@@ -4450,8 +4449,7 @@ dummy_func(
                 DECREF_INPUTS();
                 ERROR_IF(true, error);
             }
-            PyCFunctionFast cfunc =
-                (PyCFunctionFast)(void(*)(void))meth->ml_meth;
+            PyCFunctionFast cfunc = _PyCFunctionFast_CAST(meth->ml_meth);
             PyObject *res_o = cfunc(self, (args_o + 1), nargs);
             STACKREFS_TO_PYOBJECTS_CLEANUP(args_o);
             assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL));
diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h
index 9bfb13e2d9773f..3bb1991b526a7a 100644
--- a/Python/executor_cases.c.h
+++ b/Python/executor_cases.c.h
@@ -5507,7 +5507,7 @@
                 JUMP_TO_ERROR();
             }
             _PyFrame_SetStackPointer(frame, stack_pointer);
-            PyObject *res_o = ((PyCFunctionFast)(void(*)(void))cfunc)(
+            PyObject *res_o = _PyCFunctionFast_CAST(cfunc)(
                 PyCFunction_GET_SELF(callable_o),
                 args_o,
                 total_args);
@@ -5567,8 +5567,7 @@
             STAT_INC(CALL, hit);
             _PyFrame_SetStackPointer(frame, stack_pointer);
             PyCFunctionFastWithKeywords cfunc =
-            (PyCFunctionFastWithKeywords)(void(*)(void))
-            PyCFunction_GET_FUNCTION(callable_o);
+            
_PyCFunctionFastWithKeywords_CAST(PyCFunction_GET_FUNCTION(callable_o));
             stack_pointer = _PyFrame_GetStackPointer(frame);
             STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o);
             if (CONVERSION_FAILED(args_o)) {
@@ -5918,7 +5917,7 @@
             }
             _PyFrame_SetStackPointer(frame, stack_pointer);
             PyCFunctionFastWithKeywords cfunc =
-            (PyCFunctionFastWithKeywords)(void(*)(void))meth->ml_meth;
+            _PyCFunctionFastWithKeywords_CAST(meth->ml_meth);
             PyObject *res_o = cfunc(self, (args_o + 1), nargs, NULL);
             stack_pointer = _PyFrame_GetStackPointer(frame);
             STACKREFS_TO_PYOBJECTS_CLEANUP(args_o);
@@ -6073,8 +6072,7 @@
                 JUMP_TO_ERROR();
             }
             _PyFrame_SetStackPointer(frame, stack_pointer);
-            PyCFunctionFast cfunc =
-            (PyCFunctionFast)(void(*)(void))meth->ml_meth;
+            PyCFunctionFast cfunc = _PyCFunctionFast_CAST(meth->ml_meth);
             PyObject *res_o = cfunc(self, (args_o + 1), nargs);
             stack_pointer = _PyFrame_GetStackPointer(frame);
             STACKREFS_TO_PYOBJECTS_CLEANUP(args_o);
diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h
index 6fe647d6197a07..51845ebeeb2a04 100644
--- a/Python/generated_cases.c.h
+++ b/Python/generated_cases.c.h
@@ -2060,7 +2060,7 @@
                     JUMP_TO_LABEL(error);
                 }
                 _PyFrame_SetStackPointer(frame, stack_pointer);
-                PyObject *res_o = ((PyCFunctionFast)(void(*)(void))cfunc)(
+                PyObject *res_o = _PyCFunctionFast_CAST(cfunc)(
                     PyCFunction_GET_SELF(callable_o),
                     args_o,
                     total_args);
@@ -2153,8 +2153,7 @@
                 STAT_INC(CALL, hit);
                 _PyFrame_SetStackPointer(frame, stack_pointer);
                 PyCFunctionFastWithKeywords cfunc =
-                (PyCFunctionFastWithKeywords)(void(*)(void))
-                PyCFunction_GET_FUNCTION(callable_o);
+                
_PyCFunctionFastWithKeywords_CAST(PyCFunction_GET_FUNCTION(callable_o));
                 stack_pointer = _PyFrame_GetStackPointer(frame);
                 STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o);
                 if (CONVERSION_FAILED(args_o)) {
@@ -3377,8 +3376,7 @@
                     JUMP_TO_LABEL(error);
                 }
                 _PyFrame_SetStackPointer(frame, stack_pointer);
-                PyCFunctionFast cfunc =
-                (PyCFunctionFast)(void(*)(void))meth->ml_meth;
+                PyCFunctionFast cfunc = _PyCFunctionFast_CAST(meth->ml_meth);
                 PyObject *res_o = cfunc(self, (args_o + 1), nargs);
                 stack_pointer = _PyFrame_GetStackPointer(frame);
                 STACKREFS_TO_PYOBJECTS_CLEANUP(args_o);
@@ -3505,7 +3503,7 @@
                 }
                 _PyFrame_SetStackPointer(frame, stack_pointer);
                 PyCFunctionFastWithKeywords cfunc =
-                (PyCFunctionFastWithKeywords)(void(*)(void))meth->ml_meth;
+                _PyCFunctionFastWithKeywords_CAST(meth->ml_meth);
                 PyObject *res_o = cfunc(self, (args_o + 1), nargs, NULL);
                 stack_pointer = _PyFrame_GetStackPointer(frame);
                 STACKREFS_TO_PYOBJECTS_CLEANUP(args_o);

_______________________________________________
Python-checkins mailing list -- python-checkins@python.org
To unsubscribe send an email to python-checkins-le...@python.org
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: arch...@mail-archive.com

Reply via email to