• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #ifndef Py_EMSCRIPTEN_TRAMPOLINE_H
2 #define Py_EMSCRIPTEN_TRAMPOLINE_H
3 
4 #include "pycore_runtime.h"  // _PyRuntimeState
5 
6 /**
7  * C function call trampolines to mitigate bad function pointer casts.
8  *
9  * Section 6.3.2.3, paragraph 8 reads:
10  *
11  *      A pointer to a function of one type may be converted to a pointer to a
12  *      function of another type and back again; the result shall compare equal to
13  *      the original pointer. If a converted pointer is used to call a function
14  *      whose type is not compatible with the pointed-to type, the behavior is
15  *      undefined.
16  *
17  * Typical native ABIs ignore additional arguments or fill in missing values
18  * with 0/NULL in function pointer cast. Compilers do not show warnings when a
19  * function pointer is explicitly casted to an incompatible type.
20  *
21  * Bad fpcasts are an issue in WebAssembly. WASM's indirect_call has strict
22  * function signature checks. Argument count, types, and return type must match.
23  *
24  * Third party code unintentionally rely on problematic fpcasts. The call
25  * trampoline mitigates common occurrences of bad fpcasts on Emscripten.
26  */
27 
28 #if defined(__EMSCRIPTEN__) && defined(PY_CALL_TRAMPOLINE)
29 
30 void _Py_EmscriptenTrampoline_Init(_PyRuntimeState *runtime);
31 
32 PyObject*
33 _PyEM_TrampolineCall_JavaScript(PyCFunctionWithKeywords func,
34                                 PyObject* self,
35                                 PyObject* args,
36                                 PyObject* kw);
37 
38 PyObject*
39 _PyEM_TrampolineCall_Reflection(PyCFunctionWithKeywords func,
40                                 PyObject* self,
41                                 PyObject* args,
42                                 PyObject* kw);
43 
44 #define _PyEM_TrampolineCall(meth, self, args, kw) \
45     ((_PyRuntime.wasm_type_reflection_available) ? \
46         (_PyEM_TrampolineCall_Reflection((PyCFunctionWithKeywords)(meth), (self), (args), (kw))) : \
47         (_PyEM_TrampolineCall_JavaScript((PyCFunctionWithKeywords)(meth), (self), (args), (kw))))
48 
49 #define _PyCFunction_TrampolineCall(meth, self, args) \
50     _PyEM_TrampolineCall( \
51         (*(PyCFunctionWithKeywords)(void(*)(void))(meth)), (self), (args), NULL)
52 
53 #define _PyCFunctionWithKeywords_TrampolineCall(meth, self, args, kw) \
54     _PyEM_TrampolineCall((meth), (self), (args), (kw))
55 
56 #define descr_set_trampoline_call(set, obj, value, closure) \
57     ((int)_PyEM_TrampolineCall((PyCFunctionWithKeywords)(set), (obj), (value), (PyObject*)(closure)))
58 
59 #define descr_get_trampoline_call(get, obj, closure) \
60     _PyEM_TrampolineCall((PyCFunctionWithKeywords)(get), (obj), (PyObject*)(closure), NULL)
61 
62 
63 #else // defined(__EMSCRIPTEN__) && defined(PY_CALL_TRAMPOLINE)
64 
65 #define _Py_EmscriptenTrampoline_Init(runtime)
66 
67 #define _PyCFunction_TrampolineCall(meth, self, args) \
68     (meth)((self), (args))
69 
70 #define _PyCFunctionWithKeywords_TrampolineCall(meth, self, args, kw) \
71     (meth)((self), (args), (kw))
72 
73 #define descr_set_trampoline_call(set, obj, value, closure) \
74     (set)((obj), (value), (closure))
75 
76 #define descr_get_trampoline_call(get, obj, closure) \
77     (get)((obj), (closure))
78 
79 #endif // defined(__EMSCRIPTEN__) && defined(PY_CALL_TRAMPOLINE)
80 
81 #endif // ndef Py_EMSCRIPTEN_SIGNAL_H
82