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 b817ae6e68438b..00e01dbd18d3d6 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -10777,7 +10777,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, @@ -10814,7 +10815,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 e9dced654d1492..590a1a51851e2e 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 938a80fe665c0b..659e66859b5c50 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 97bffce8d82767..8820d82ed96b29 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)) { @@ -3389,8 +3388,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); @@ -3517,7 +3515,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);