Skip to content

Commit 3793526

Browse files
authored
gh-132097: use a macro for semantically casting function pointers (#132406)
1 parent f3d877a commit 3793526

File tree

9 files changed

+47
-31
lines changed

9 files changed

+47
-31
lines changed

Include/internal/pycore_emscripten_trampoline.h

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,17 +37,18 @@ _PyEM_TrampolineCall(PyCFunctionWithKeywords func,
3737
PyObject* kw);
3838

3939
#define _PyCFunction_TrampolineCall(meth, self, args) \
40-
_PyEM_TrampolineCall( \
41-
(*(PyCFunctionWithKeywords)(void(*)(void))(meth)), (self), (args), NULL)
40+
_PyEM_TrampolineCall(*_PyCFunctionWithKeywords_CAST(meth), (self), (args), NULL)
4241

4342
#define _PyCFunctionWithKeywords_TrampolineCall(meth, self, args, kw) \
4443
_PyEM_TrampolineCall((meth), (self), (args), (kw))
4544

46-
#define descr_set_trampoline_call(set, obj, value, closure) \
47-
((int)_PyEM_TrampolineCall((PyCFunctionWithKeywords)(set), (obj), (value), (PyObject*)(closure)))
45+
#define descr_set_trampoline_call(set, obj, value, closure) \
46+
((int)_PyEM_TrampolineCall(_PyCFunctionWithKeywords_CAST(set), (obj), \
47+
(value), (PyObject*)(closure)))
4848

49-
#define descr_get_trampoline_call(get, obj, closure) \
50-
_PyEM_TrampolineCall((PyCFunctionWithKeywords)(get), (obj), (PyObject*)(closure), NULL)
49+
#define descr_get_trampoline_call(get, obj, closure) \
50+
_PyEM_TrampolineCall(_PyCFunctionWithKeywords_CAST(get), (obj), \
51+
(PyObject*)(closure), NULL)
5152

5253

5354
#else // defined(__EMSCRIPTEN__) && defined(PY_CALL_TRAMPOLINE)

Include/methodobject.h

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ typedef PyObject *(*PyCMethod)(PyObject *, PyTypeObject *, PyObject *const *,
3333
typedef PyCFunctionFast _PyCFunctionFast;
3434
typedef PyCFunctionFastWithKeywords _PyCFunctionFastWithKeywords;
3535

36-
// Cast an function to the PyCFunction type to use it with PyMethodDef.
36+
// Cast a function to the PyCFunction type to use it with PyMethodDef.
3737
//
3838
// This macro can be used to prevent compiler warnings if the first parameter
3939
// uses a different pointer type than PyObject* (ex: METH_VARARGS and METH_O
@@ -49,8 +49,17 @@ typedef PyCFunctionFastWithKeywords _PyCFunctionFastWithKeywords;
4949
// used to prevent a compiler warning. If the function has a single parameter,
5050
// it triggers an undefined behavior when Python calls it with 2 parameters
5151
// (bpo-33012).
52-
#define _PyCFunction_CAST(func) \
53-
_Py_CAST(PyCFunction, _Py_CAST(void(*)(void), (func)))
52+
#define _PyCFunction_CAST(func) \
53+
_Py_FUNC_CAST(PyCFunction, func)
54+
// The macros below are given for semantic convenience, allowing users
55+
// to see whether a cast to suppress an undefined behavior is necessary.
56+
// Note: At runtime, the original function signature must be respected.
57+
#define _PyCFunctionFast_CAST(func) \
58+
_Py_FUNC_CAST(PyCFunctionFast, func)
59+
#define _PyCFunctionWithKeywords_CAST(func) \
60+
_Py_FUNC_CAST(PyCFunctionWithKeywords, func)
61+
#define _PyCFunctionFastWithKeywords_CAST(func) \
62+
_Py_FUNC_CAST(PyCFunctionFastWithKeywords, func)
5463

5564
PyAPI_FUNC(PyCFunction) PyCFunction_GetFunction(PyObject *);
5665
PyAPI_FUNC(PyObject *) PyCFunction_GetSelf(PyObject *);

Include/pyport.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,16 @@
3636
// Macro to use the more powerful/dangerous C-style cast even in C++.
3737
#define _Py_CAST(type, expr) ((type)(expr))
3838

39+
// Cast a function to another function type T.
40+
//
41+
// The macro first casts the function to the "void func(void)" type
42+
// to prevent compiler warnings.
43+
//
44+
// Note that using this cast only prevents the compiler from emitting
45+
// warnings, but does not prevent an undefined behavior at runtime if
46+
// the original function signature is not respected.
47+
#define _Py_FUNC_CAST(T, func) _Py_CAST(T, _Py_CAST(void(*)(void), (func)))
48+
3949
// Static inline functions should use _Py_NULL rather than using directly NULL
4050
// to prevent C++ compiler warnings. On C23 and newer and on C++11 and newer,
4151
// _Py_NULL is defined as nullptr.

Objects/descrobject.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -519,7 +519,7 @@ wrapperdescr_raw_call(PyWrapperDescrObject *descr, PyObject *self,
519519
wrapperfunc wrapper = descr->d_base->wrapper;
520520

521521
if (descr->d_base->flags & PyWrapperFlag_KEYWORDS) {
522-
wrapperfunc_kwds wk = (wrapperfunc_kwds)(void(*)(void))wrapper;
522+
wrapperfunc_kwds wk = _Py_FUNC_CAST(wrapperfunc_kwds, wrapper);
523523
return (*wk)(self, args, descr->d_wrapped, kwds);
524524
}
525525

Objects/methodobject.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -567,7 +567,7 @@ cfunction_call(PyObject *func, PyObject *args, PyObject *kwargs)
567567
PyObject *result;
568568
if (flags & METH_KEYWORDS) {
569569
result = _PyCFunctionWithKeywords_TrampolineCall(
570-
(*(PyCFunctionWithKeywords)(void(*)(void))meth),
570+
*_PyCFunctionWithKeywords_CAST(meth),
571571
self, args, kwargs);
572572
}
573573
else {

Objects/typeobject.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10807,7 +10807,8 @@ static pytype_slotdef slotdefs[] = {
1080710807
"__repr__($self, /)\n--\n\nReturn repr(self)."),
1080810808
TPSLOT(__hash__, tp_hash, slot_tp_hash, wrap_hashfunc,
1080910809
"__hash__($self, /)\n--\n\nReturn hash(self)."),
10810-
FLSLOT(__call__, tp_call, slot_tp_call, (wrapperfunc)(void(*)(void))wrap_call,
10810+
FLSLOT(__call__, tp_call, slot_tp_call,
10811+
_Py_FUNC_CAST(wrapperfunc, wrap_call),
1081110812
"__call__($self, /, *args, **kwargs)\n--\n\nCall self as a function.",
1081210813
PyWrapperFlag_KEYWORDS),
1081310814
TPSLOT(__str__, tp_str, slot_tp_str, wrap_unaryfunc,
@@ -10844,7 +10845,8 @@ static pytype_slotdef slotdefs[] = {
1084410845
TPSLOT(__delete__, tp_descr_set, slot_tp_descr_set,
1084510846
wrap_descr_delete,
1084610847
"__delete__($self, instance, /)\n--\n\nDelete an attribute of instance."),
10847-
FLSLOT(__init__, tp_init, slot_tp_init, (wrapperfunc)(void(*)(void))wrap_init,
10848+
FLSLOT(__init__, tp_init, slot_tp_init,
10849+
_Py_FUNC_CAST(wrapperfunc, wrap_init),
1084810850
"__init__($self, /, *args, **kwargs)\n--\n\n"
1084910851
"Initialize self. See help(type(self)) for accurate signature.",
1085010852
PyWrapperFlag_KEYWORDS),

Python/bytecodes.c

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4170,7 +4170,7 @@ dummy_func(
41704170
DECREF_INPUTS();
41714171
ERROR_IF(true, error);
41724172
}
4173-
PyObject *res_o = ((PyCFunctionFast)(void(*)(void))cfunc)(
4173+
PyObject *res_o = _PyCFunctionFast_CAST(cfunc)(
41744174
PyCFunction_GET_SELF(callable_o),
41754175
args_o,
41764176
total_args);
@@ -4202,8 +4202,7 @@ dummy_func(
42024202
STAT_INC(CALL, hit);
42034203
/* res = func(self, arguments, nargs, kwnames) */
42044204
PyCFunctionFastWithKeywords cfunc =
4205-
(PyCFunctionFastWithKeywords)(void(*)(void))
4206-
PyCFunction_GET_FUNCTION(callable_o);
4205+
_PyCFunctionFastWithKeywords_CAST(PyCFunction_GET_FUNCTION(callable_o));
42074206

42084207
STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o);
42094208
if (CONVERSION_FAILED(args_o)) {
@@ -4371,7 +4370,7 @@ dummy_func(
43714370
ERROR_IF(true, error);
43724371
}
43734372
PyCFunctionFastWithKeywords cfunc =
4374-
(PyCFunctionFastWithKeywords)(void(*)(void))meth->ml_meth;
4373+
_PyCFunctionFastWithKeywords_CAST(meth->ml_meth);
43754374
PyObject *res_o = cfunc(self, (args_o + 1), nargs, NULL);
43764375
STACKREFS_TO_PYOBJECTS_CLEANUP(args_o);
43774376
assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL));
@@ -4450,8 +4449,7 @@ dummy_func(
44504449
DECREF_INPUTS();
44514450
ERROR_IF(true, error);
44524451
}
4453-
PyCFunctionFast cfunc =
4454-
(PyCFunctionFast)(void(*)(void))meth->ml_meth;
4452+
PyCFunctionFast cfunc = _PyCFunctionFast_CAST(meth->ml_meth);
44554453
PyObject *res_o = cfunc(self, (args_o + 1), nargs);
44564454
STACKREFS_TO_PYOBJECTS_CLEANUP(args_o);
44574455
assert((res_o != NULL) ^ (_PyErr_Occurred(tstate) != NULL));

Python/executor_cases.c.h

Lines changed: 4 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Python/generated_cases.c.h

Lines changed: 4 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)
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