From 09fb71510fe0aca9f9cf0853461ad55c1712e6bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Thu, 10 Apr 2025 14:12:40 +0200 Subject: [PATCH 1/7] feat(semantics): use a macro for suppressing UB warnings --- Include/internal/pycore_emscripten_trampoline.h | 13 +++++++------ Include/methodobject.h | 12 ++++++++++-- Include/pyport.h | 1 + Objects/descrobject.c | 2 +- Objects/methodobject.c | 2 +- Objects/typeobject.c | 6 ++++-- Python/bytecodes.c | 10 ++++------ Python/executor_cases.c.h | 10 ++++------ Python/generated_cases.c.h | 10 ++++------ 9 files changed, 36 insertions(+), 30 deletions(-) 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..7b566299644fbc 100644 --- a/Include/methodobject.h +++ b/Include/methodobject.h @@ -49,8 +49,16 @@ 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) +// Other casts are given for semantic conveniences, allowing +// users to see whether a cast to suppress a UB is necessary. +#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..7b1d92a7969b73 100644 --- a/Include/pyport.h +++ b/Include/pyport.h @@ -35,6 +35,7 @@ #endif // Macro to use the more powerful/dangerous C-style cast even in C++. #define _Py_CAST(type, expr) ((type)(expr)) +#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, 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 1f459dea44192c..0b3cc0c9d4230e 100644 --- a/Objects/methodobject.c +++ b/Objects/methodobject.c @@ -563,7 +563,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 b92eaefc90d0af..162d44178cb028 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -10758,7 +10758,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, @@ -10795,7 +10796,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_call), "__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 53da324ee5ab89..96b72a5399dc3d 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -4117,7 +4117,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); @@ -4149,8 +4149,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)) { @@ -4318,7 +4317,7 @@ dummy_func( ERROR_IF(true, error); } PyCFunctionFastWithKeywords cfunc = - (PyCFunctionFastWithKeywords)(void(*)(void))meth->ml_meth; + _PyCFunctionFastWithKeywords_CAST(meth->ml_met); PyObject *res_o = cfunc(self, (args_o + 1), nargs, NULL); STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); @@ -4397,8 +4396,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 3457ff0d6a1c06..7aa0e4a22c3363 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -5472,7 +5472,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); @@ -5532,8 +5532,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)) { @@ -5883,7 +5882,7 @@ } _PyFrame_SetStackPointer(frame, stack_pointer); PyCFunctionFastWithKeywords cfunc = - (PyCFunctionFastWithKeywords)(void(*)(void))meth->ml_meth; + _PyCFunctionFastWithKeywords_CAST(meth->ml_met); PyObject *res_o = cfunc(self, (args_o + 1), nargs, NULL); stack_pointer = _PyFrame_GetStackPointer(frame); STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); @@ -6038,8 +6037,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 fb4ab92c635d9e..a502a06f67fe62 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -2051,7 +2051,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); @@ -2144,8 +2144,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)) { @@ -3380,8 +3379,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); @@ -3508,7 +3506,7 @@ } _PyFrame_SetStackPointer(frame, stack_pointer); PyCFunctionFastWithKeywords cfunc = - (PyCFunctionFastWithKeywords)(void(*)(void))meth->ml_meth; + _PyCFunctionFastWithKeywords_CAST(meth->ml_met); PyObject *res_o = cfunc(self, (args_o + 1), nargs, NULL); stack_pointer = _PyFrame_GetStackPointer(frame); STACKREFS_TO_PYOBJECTS_CLEANUP(args_o); From f6d6df36ba8bd21465fef9afd0b8d05b05555ec2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Fri, 11 Apr 2025 17:19:15 +0200 Subject: [PATCH 2/7] fixup --- Python/bytecodes.c | 2 +- Python/executor_cases.c.h | 2 +- Python/generated_cases.c.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 209cdc26ee9e96..590a1a51851e2e 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -4370,7 +4370,7 @@ dummy_func( ERROR_IF(true, error); } PyCFunctionFastWithKeywords cfunc = - _PyCFunctionFastWithKeywords_CAST(meth->ml_met); + _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)); diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index 45fdfab06a8ab4..659e66859b5c50 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -5917,7 +5917,7 @@ } _PyFrame_SetStackPointer(frame, stack_pointer); PyCFunctionFastWithKeywords cfunc = - _PyCFunctionFastWithKeywords_CAST(meth->ml_met); + _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); diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 5ccb9935e59121..8820d82ed96b29 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -3515,7 +3515,7 @@ } _PyFrame_SetStackPointer(frame, stack_pointer); PyCFunctionFastWithKeywords cfunc = - _PyCFunctionFastWithKeywords_CAST(meth->ml_met); + _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); From 21535077fc27d3ca4f280a21d2cd1b3ffcf3eeca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Fri, 11 Apr 2025 17:22:21 +0200 Subject: [PATCH 3/7] fixup --- Objects/typeobject.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 29b7d11cc3bbc5..00e01dbd18d3d6 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -10816,7 +10816,7 @@ static pytype_slotdef slotdefs[] = { wrap_descr_delete, "__delete__($self, instance, /)\n--\n\nDelete an attribute of instance."), FLSLOT(__init__, tp_init, slot_tp_init, - _Py_FUNC_CAST(wrapperfunc, wrap_call), + _Py_FUNC_CAST(wrapperfunc, wrap_init), "__init__($self, /, *args, **kwargs)\n--\n\n" "Initialize self. See help(type(self)) for accurate signature.", PyWrapperFlag_KEYWORDS), From efa7bdcb47376abdb5f7e5f4ea7d1fce16244363 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Fri, 18 Apr 2025 10:17:05 +0200 Subject: [PATCH 4/7] Update Include/methodobject.h Co-authored-by: Victor Stinner --- Include/methodobject.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Include/methodobject.h b/Include/methodobject.h index 7b566299644fbc..5371bcc499aeef 100644 --- a/Include/methodobject.h +++ b/Include/methodobject.h @@ -52,7 +52,7 @@ typedef PyCFunctionFastWithKeywords _PyCFunctionFastWithKeywords; #define _PyCFunction_CAST(func) \ _Py_FUNC_CAST(PyCFunction, func) // Other casts are given for semantic conveniences, allowing -// users to see whether a cast to suppress a UB is necessary. +// users to see whether a cast to suppress an undefined behavior is necessary. #define _PyCFunctionFast_CAST(func) \ _Py_FUNC_CAST(PyCFunctionFast, func) #define _PyCFunctionWithKeywords_CAST(func) \ From 4bcff7f00a01c074e042b4e7df086402f19edebf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Fri, 18 Apr 2025 10:22:45 +0200 Subject: [PATCH 5/7] address review --- Include/methodobject.h | 2 +- Include/pyport.h | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/Include/methodobject.h b/Include/methodobject.h index 5371bcc499aeef..f172695af3d519 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 diff --git a/Include/pyport.h b/Include/pyport.h index 7b1d92a7969b73..a3f50ec4b699c1 100644 --- a/Include/pyport.h +++ b/Include/pyport.h @@ -35,6 +35,14 @@ #endif // 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 From 398e139d02bcb79a8372800f1f278b4a51110ced Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Fri, 18 Apr 2025 10:26:41 +0200 Subject: [PATCH 6/7] improve wording --- Include/methodobject.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Include/methodobject.h b/Include/methodobject.h index f172695af3d519..e6ec6421d1e59d 100644 --- a/Include/methodobject.h +++ b/Include/methodobject.h @@ -51,8 +51,9 @@ typedef PyCFunctionFastWithKeywords _PyCFunctionFastWithKeywords; // (bpo-33012). #define _PyCFunction_CAST(func) \ _Py_FUNC_CAST(PyCFunction, func) -// Other casts are given for semantic conveniences, allowing -// users to see whether a cast to suppress an undefined behavior is necessary. +// 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) \ From 8f567fa599e4ec8ecf13078236130239974c062e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Fri, 18 Apr 2025 11:28:46 +0200 Subject: [PATCH 7/7] Update Include/pyport.h Co-authored-by: Victor Stinner --- Include/pyport.h | 1 + 1 file changed, 1 insertion(+) diff --git a/Include/pyport.h b/Include/pyport.h index a3f50ec4b699c1..ebce31f1d14a01 100644 --- a/Include/pyport.h +++ b/Include/pyport.h @@ -35,6 +35,7 @@ #endif // 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 pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy