From f0bc69485677ae8973685866ada0982976d3878f Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Thu, 31 Mar 2022 10:02:34 +0200 Subject: bpo-47164: Add _PyCFunction_CAST() macro (GH-32192) Use the macro in C files of the Python/ directory. --- Doc/c-api/structures.rst | 3 +++ Include/methodobject.h | 18 ++++++++++++++++++ Python/_warnings.c | 6 +++--- Python/bltinmodule.c | 26 +++++++++++++------------- Python/context.c | 2 +- Python/hamt.c | 18 +++++++++--------- Python/sysmodule.c | 18 +++++++++--------- Python/traceback.c | 2 +- 8 files changed, 57 insertions(+), 36 deletions(-) diff --git a/Doc/c-api/structures.rst b/Doc/c-api/structures.rst index 49f2a61..3270d7d 100644 --- a/Doc/c-api/structures.rst +++ b/Doc/c-api/structures.rst @@ -342,6 +342,9 @@ There are these calling conventions: hold a reference to the module or object instance. In all cases the second parameter will be ``NULL``. + The function must have 2 parameters. Since the second parameter is unused, + :c:macro:`Py_UNUSED` can be used to prevent a compiler warning. + .. data:: METH_O diff --git a/Include/methodobject.h b/Include/methodobject.h index 5d2e06c..959e775 100644 --- a/Include/methodobject.h +++ b/Include/methodobject.h @@ -26,6 +26,24 @@ typedef PyObject *(*_PyCFunctionFastWithKeywords) (PyObject *, typedef PyObject *(*PyCMethod)(PyObject *, PyTypeObject *, PyObject *const *, size_t, PyObject *); +// Cast an 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 +// calling conventions). +// +// The macro can also be used for METH_FASTCALL and METH_VARARGS|METH_KEYWORDS +// calling conventions to avoid compiler warnings because the function has more +// than 2 parameters. The macro first casts the function to the +// "void func(void)" type to prevent compiler warnings. +// +// If a function is declared with the METH_NOARGS calling convention, it must +// have 2 parameters. Since the second parameter is unused, Py_UNUSED() can be +// 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) ((PyCFunction)(void(*)(void))(func)) + PyAPI_FUNC(PyCFunction) PyCFunction_GetFunction(PyObject *); PyAPI_FUNC(PyObject *) PyCFunction_GetSelf(PyObject *); PyAPI_FUNC(int) PyCFunction_GetFlags(PyObject *); diff --git a/Python/_warnings.c b/Python/_warnings.c index be962e7..942308b 100644 --- a/Python/_warnings.c +++ b/Python/_warnings.c @@ -1078,7 +1078,7 @@ warnings_warn_explicit(PyObject *self, PyObject *args, PyObject *kwds) } static PyObject * -warnings_filters_mutated(PyObject *self, PyObject *args) +warnings_filters_mutated(PyObject *self, PyObject *Py_UNUSED(args)) { PyInterpreterState *interp = get_current_interp(); if (interp == NULL) { @@ -1353,9 +1353,9 @@ PyDoc_STRVAR(warn_explicit_doc, static PyMethodDef warnings_functions[] = { WARNINGS_WARN_METHODDEF - {"warn_explicit", (PyCFunction)(void(*)(void))warnings_warn_explicit, + {"warn_explicit", _PyCFunction_CAST(warnings_warn_explicit), METH_VARARGS | METH_KEYWORDS, warn_explicit_doc}, - {"_filters_mutated", (PyCFunction)warnings_filters_mutated, METH_NOARGS, + {"_filters_mutated", _PyCFunction_CAST(warnings_filters_mutated), METH_NOARGS, NULL}, /* XXX(brett.cannon): add showwarning? */ /* XXX(brett.cannon): Reasonable to add formatwarning? */ diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c index 332f4cb..9cfecc5 100644 --- a/Python/bltinmodule.c +++ b/Python/bltinmodule.c @@ -613,7 +613,7 @@ filter_reduce(filterobject *lz, PyObject *Py_UNUSED(ignored)) PyDoc_STRVAR(reduce_doc, "Return state information for pickling."); static PyMethodDef filter_methods[] = { - {"__reduce__", (PyCFunction)filter_reduce, METH_NOARGS, reduce_doc}, + {"__reduce__", _PyCFunction_CAST(filter_reduce), METH_NOARGS, reduce_doc}, {NULL, NULL} /* sentinel */ }; @@ -1354,7 +1354,7 @@ map_reduce(mapobject *lz, PyObject *Py_UNUSED(ignored)) } static PyMethodDef map_methods[] = { - {"__reduce__", (PyCFunction)map_reduce, METH_NOARGS, reduce_doc}, + {"__reduce__", _PyCFunction_CAST(map_reduce), METH_NOARGS, reduce_doc}, {NULL, NULL} /* sentinel */ }; @@ -2321,7 +2321,7 @@ PyDoc_STRVAR(builtin_sorted__doc__, "reverse flag can be set to request the result in descending order."); #define BUILTIN_SORTED_METHODDEF \ - {"sorted", (PyCFunction)(void(*)(void))builtin_sorted, METH_FASTCALL | METH_KEYWORDS, builtin_sorted__doc__}, + {"sorted", _PyCFunction_CAST(builtin_sorted), METH_FASTCALL | METH_KEYWORDS, builtin_sorted__doc__}, static PyObject * builtin_sorted(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) @@ -2839,8 +2839,8 @@ zip_setstate(zipobject *lz, PyObject *state) } static PyMethodDef zip_methods[] = { - {"__reduce__", (PyCFunction)zip_reduce, METH_NOARGS, reduce_doc}, - {"__setstate__", (PyCFunction)zip_setstate, METH_O, setstate_doc}, + {"__reduce__", _PyCFunction_CAST(zip_reduce), METH_NOARGS, reduce_doc}, + {"__setstate__", _PyCFunction_CAST(zip_setstate), METH_O, setstate_doc}, {NULL} /* sentinel */ }; @@ -2904,7 +2904,7 @@ PyTypeObject PyZip_Type = { static PyMethodDef builtin_methods[] = { - {"__build_class__", (PyCFunction)(void(*)(void))builtin___build_class__, + {"__build_class__", _PyCFunction_CAST(builtin___build_class__), METH_FASTCALL | METH_KEYWORDS, build_class_doc}, BUILTIN___IMPORT___METHODDEF BUILTIN_ABS_METHODDEF @@ -2912,17 +2912,17 @@ static PyMethodDef builtin_methods[] = { BUILTIN_ANY_METHODDEF BUILTIN_ASCII_METHODDEF BUILTIN_BIN_METHODDEF - {"breakpoint", (PyCFunction)(void(*)(void))builtin_breakpoint, METH_FASTCALL | METH_KEYWORDS, breakpoint_doc}, + {"breakpoint", _PyCFunction_CAST(builtin_breakpoint), METH_FASTCALL | METH_KEYWORDS, breakpoint_doc}, BUILTIN_CALLABLE_METHODDEF BUILTIN_CHR_METHODDEF BUILTIN_COMPILE_METHODDEF BUILTIN_DELATTR_METHODDEF - {"dir", builtin_dir, METH_VARARGS, dir_doc}, + {"dir", builtin_dir, METH_VARARGS, dir_doc}, BUILTIN_DIVMOD_METHODDEF BUILTIN_EVAL_METHODDEF BUILTIN_EXEC_METHODDEF BUILTIN_FORMAT_METHODDEF - {"getattr", (PyCFunction)(void(*)(void))builtin_getattr, METH_FASTCALL, getattr_doc}, + {"getattr", _PyCFunction_CAST(builtin_getattr), METH_FASTCALL, getattr_doc}, BUILTIN_GLOBALS_METHODDEF BUILTIN_HASATTR_METHODDEF BUILTIN_HASH_METHODDEF @@ -2931,13 +2931,13 @@ static PyMethodDef builtin_methods[] = { BUILTIN_INPUT_METHODDEF BUILTIN_ISINSTANCE_METHODDEF BUILTIN_ISSUBCLASS_METHODDEF - {"iter", (PyCFunction)(void(*)(void))builtin_iter, METH_FASTCALL, iter_doc}, + {"iter", _PyCFunction_CAST(builtin_iter), METH_FASTCALL, iter_doc}, BUILTIN_AITER_METHODDEF BUILTIN_LEN_METHODDEF BUILTIN_LOCALS_METHODDEF - {"max", (PyCFunction)(void(*)(void))builtin_max, METH_VARARGS | METH_KEYWORDS, max_doc}, - {"min", (PyCFunction)(void(*)(void))builtin_min, METH_VARARGS | METH_KEYWORDS, min_doc}, - {"next", (PyCFunction)(void(*)(void))builtin_next, METH_FASTCALL, next_doc}, + {"max", _PyCFunction_CAST(builtin_max), METH_VARARGS | METH_KEYWORDS, max_doc}, + {"min", _PyCFunction_CAST(builtin_min), METH_VARARGS | METH_KEYWORDS, min_doc}, + {"next", _PyCFunction_CAST(builtin_next), METH_FASTCALL, next_doc}, BUILTIN_ANEXT_METHODDEF BUILTIN_OCT_METHODDEF BUILTIN_ORD_METHODDEF diff --git a/Python/context.c b/Python/context.c index f3033d9..a77cd14 100644 --- a/Python/context.c +++ b/Python/context.c @@ -685,7 +685,7 @@ static PyMethodDef PyContext_methods[] = { _CONTEXTVARS_CONTEXT_KEYS_METHODDEF _CONTEXTVARS_CONTEXT_VALUES_METHODDEF _CONTEXTVARS_CONTEXT_COPY_METHODDEF - {"run", (PyCFunction)(void(*)(void))context_run, METH_FASTCALL | METH_KEYWORDS, NULL}, + {"run", _PyCFunction_CAST(context_run), METH_FASTCALL | METH_KEYWORDS, NULL}, {NULL, NULL} }; diff --git a/Python/hamt.c b/Python/hamt.c index cbfe445..c3cb4e6 100644 --- a/Python/hamt.c +++ b/Python/hamt.c @@ -2845,14 +2845,14 @@ hamt_py_values(PyHamtObject *self, PyObject *args) } static PyObject * -hamt_py_keys(PyHamtObject *self, PyObject *args) +hamt_py_keys(PyHamtObject *self, PyObject *Py_UNUSED(args)) { return _PyHamt_NewIterKeys(self); } #ifdef Py_DEBUG static PyObject * -hamt_py_dump(PyHamtObject *self, PyObject *args) +hamt_py_dump(PyHamtObject *self, PyObject *Py_UNUSED(args)) { return hamt_dump(self); } @@ -2860,14 +2860,14 @@ hamt_py_dump(PyHamtObject *self, PyObject *args) static PyMethodDef PyHamt_methods[] = { - {"set", (PyCFunction)hamt_py_set, METH_VARARGS, NULL}, - {"get", (PyCFunction)hamt_py_get, METH_VARARGS, NULL}, - {"delete", (PyCFunction)hamt_py_delete, METH_O, NULL}, - {"items", (PyCFunction)hamt_py_items, METH_NOARGS, NULL}, - {"keys", (PyCFunction)hamt_py_keys, METH_NOARGS, NULL}, - {"values", (PyCFunction)hamt_py_values, METH_NOARGS, NULL}, + {"set", _PyCFunction_CAST(hamt_py_set), METH_VARARGS, NULL}, + {"get", _PyCFunction_CAST(hamt_py_get), METH_VARARGS, NULL}, + {"delete", _PyCFunction_CAST(hamt_py_delete), METH_O, NULL}, + {"items", _PyCFunction_CAST(hamt_py_items), METH_NOARGS, NULL}, + {"keys", _PyCFunction_CAST(hamt_py_keys), METH_NOARGS, NULL}, + {"values", _PyCFunction_CAST(hamt_py_values), METH_NOARGS, NULL}, #ifdef Py_DEBUG - {"__dump__", (PyCFunction)hamt_py_dump, METH_NOARGS, NULL}, + {"__dump__", _PyCFunction_CAST(hamt_py_dump), METH_NOARGS, NULL}, #endif {NULL, NULL} }; diff --git a/Python/sysmodule.c b/Python/sysmodule.c index 6322af5..5765e9e 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -1929,8 +1929,8 @@ sys_getandroidapilevel_impl(PyObject *module) static PyMethodDef sys_methods[] = { /* Might as well keep this in alphabetic order */ SYS_ADDAUDITHOOK_METHODDEF - {"audit", (PyCFunction)(void(*)(void))sys_audit, METH_FASTCALL, audit_doc }, - {"breakpointhook", (PyCFunction)(void(*)(void))sys_breakpointhook, + {"audit", _PyCFunction_CAST(sys_audit), METH_FASTCALL, audit_doc }, + {"breakpointhook", _PyCFunction_CAST(sys_breakpointhook), METH_FASTCALL | METH_KEYWORDS, breakpointhook_doc}, SYS__CLEAR_TYPE_CACHE_METHODDEF SYS__CURRENT_FRAMES_METHODDEF @@ -1944,18 +1944,18 @@ static PyMethodDef sys_methods[] = { SYS_GETDLOPENFLAGS_METHODDEF SYS_GETALLOCATEDBLOCKS_METHODDEF #ifdef Py_STATS - {"getdxp", _Py_GetDXProfile, METH_VARARGS}, + {"getdxp", _Py_GetDXProfile, METH_VARARGS}, #endif SYS_GETFILESYSTEMENCODING_METHODDEF SYS_GETFILESYSTEMENCODEERRORS_METHODDEF SYS__GETQUICKENEDCOUNT_METHODDEF #ifdef Py_TRACE_REFS - {"getobjects", _Py_GetObjects, METH_VARARGS}, + {"getobjects", _Py_GetObjects, METH_VARARGS}, #endif SYS_GETTOTALREFCOUNT_METHODDEF SYS_GETREFCOUNT_METHODDEF SYS_GETRECURSIONLIMIT_METHODDEF - {"getsizeof", (PyCFunction)(void(*)(void))sys_getsizeof, + {"getsizeof", _PyCFunction_CAST(sys_getsizeof), METH_VARARGS | METH_KEYWORDS, getsizeof_doc}, SYS__GETFRAME_METHODDEF SYS_GETWINDOWSVERSION_METHODDEF @@ -1966,21 +1966,21 @@ static PyMethodDef sys_methods[] = { SYS_SETSWITCHINTERVAL_METHODDEF SYS_GETSWITCHINTERVAL_METHODDEF SYS_SETDLOPENFLAGS_METHODDEF - {"setprofile", sys_setprofile, METH_O, setprofile_doc}, + {"setprofile", sys_setprofile, METH_O, setprofile_doc}, SYS_GETPROFILE_METHODDEF SYS_SETRECURSIONLIMIT_METHODDEF - {"settrace", sys_settrace, METH_O, settrace_doc}, + {"settrace", sys_settrace, METH_O, settrace_doc}, SYS_GETTRACE_METHODDEF SYS_CALL_TRACING_METHODDEF SYS__DEBUGMALLOCSTATS_METHODDEF SYS_SET_COROUTINE_ORIGIN_TRACKING_DEPTH_METHODDEF SYS_GET_COROUTINE_ORIGIN_TRACKING_DEPTH_METHODDEF - {"set_asyncgen_hooks", (PyCFunction)(void(*)(void))sys_set_asyncgen_hooks, + {"set_asyncgen_hooks", _PyCFunction_CAST(sys_set_asyncgen_hooks), METH_VARARGS | METH_KEYWORDS, set_asyncgen_hooks_doc}, SYS_GET_ASYNCGEN_HOOKS_METHODDEF SYS_GETANDROIDAPILEVEL_METHODDEF SYS_UNRAISABLEHOOK_METHODDEF - {NULL, NULL} /* sentinel */ + {NULL, NULL} // sentinel }; diff --git a/Python/traceback.c b/Python/traceback.c index f5c1849..0d0eb95 100644 --- a/Python/traceback.c +++ b/Python/traceback.c @@ -149,7 +149,7 @@ tb_next_set(PyTracebackObject *self, PyObject *new_next, void *Py_UNUSED(_)) static PyMethodDef tb_methods[] = { - {"__dir__", (PyCFunction)tb_dir, METH_NOARGS}, + {"__dir__", _PyCFunction_CAST(tb_dir), METH_NOARGS}, {NULL, NULL, 0, NULL}, }; -- cgit v0.12