diff --git a/Include/moduleobject.h b/Include/moduleobject.h index 2a17c891dda811..d8c0618f54daee 100644 --- a/Include/moduleobject.h +++ b/Include/moduleobject.h @@ -116,6 +116,48 @@ struct PyModuleDef { freefunc m_free; }; +#if defined(_PyHack_check_version_on_modinit) && defined(Py_BUILD_CORE) +/* The mechanism for the check has been implemented on Python 3.15+: + * https://github.com/python/cpython/pull/137212 + * In Fedora, we need this in older Pythons too: + * if somebody attempts to import a module compiled for a different Python version, + * instead of segmentation fault a meaningful error is raised. + */ +PyAPI_DATA(const unsigned long) Py_Version; + +static inline int +_PyHack_CheckInternalAPIVersion(const char *mod_name) +{ + if (PY_VERSION_HEX != Py_Version) { + PyErr_Format( + PyExc_ImportError, + "internal Python C API version mismatch: " + "module %s compiled with %lu.%lu.%lu; runtime version is %lu.%lu.%lu", + mod_name, + (const unsigned long)((PY_VERSION_HEX >> 24) & 0xFF), + (const unsigned long)((PY_VERSION_HEX >> 16) & 0xFF), + (const unsigned long)((PY_VERSION_HEX >> 8) & 0xFF), + (const unsigned long)((Py_Version >> 24) & 0xFF), + (const unsigned long)((Py_Version >> 16) & 0xFF), + (const unsigned long)((Py_Version >> 8) & 0xFF) + ); + return -1; + } + return 0; +} + +static inline PyObject * +PyModuleDef_Init_with_check(PyModuleDef *def) +{ + if (_PyHack_CheckInternalAPIVersion(def->m_name) < 0) { + return NULL; + } + return PyModuleDef_Init(def); +} + +#define PyModuleDef_Init PyModuleDef_Init_with_check +#endif + #ifdef __cplusplus } #endif diff --git a/Makefile.pre.in b/Makefile.pre.in index 38a355a23f2aab..f2d909c8c9d5ce 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -3415,3 +3415,6 @@ MODULE__MULTIBYTECODEC_DEPS=$(srcdir)/Modules/cjkcodecs/multibytecodec.h # Local Variables: # mode: makefile # End: + +# Fedora-specific, downstream only +CFLAGS += -D_PyHack_check_version_on_modinit=1 diff --git a/Modules/_tkinter.c b/Modules/_tkinter.c index 2216de509e939c..e5438aa0b298a7 100644 --- a/Modules/_tkinter.c +++ b/Modules/_tkinter.c @@ -3489,6 +3489,10 @@ static struct PyModuleDef _tkintermodule = { PyMODINIT_FUNC PyInit__tkinter(void) { + if (_PyHack_CheckInternalAPIVersion("_tkinter") < 0) { + return NULL; + } + PyObject *m, *uexe, *cexe; tcl_lock = PyThread_allocate_lock(); diff --git a/Modules/_tracemalloc.c b/Modules/_tracemalloc.c index be71fc9fc9c341..5cb33c5b26804e 100644 --- a/Modules/_tracemalloc.c +++ b/Modules/_tracemalloc.c @@ -215,6 +215,10 @@ static struct PyModuleDef module_def = { PyMODINIT_FUNC PyInit__tracemalloc(void) { + if (_PyHack_CheckInternalAPIVersion("_tracemalloc") < 0) { + return NULL; + } + PyObject *mod = PyModule_Create(&module_def); if (mod == NULL) { return NULL; diff --git a/Modules/readline.c b/Modules/readline.c index 8475846eefc905..bce782995b4888 100644 --- a/Modules/readline.c +++ b/Modules/readline.c @@ -1604,6 +1604,10 @@ static struct PyModuleDef readlinemodule = { PyMODINIT_FUNC PyInit_readline(void) { + if (_PyHack_CheckInternalAPIVersion("readline") < 0) { + return NULL; + } + const char *backend = "readline"; PyObject *m; readlinestate *mod_state; diff --git a/Objects/moduleobject.c b/Objects/moduleobject.c index b68584b5dd571d..cbf95dc92acfdc 100644 --- a/Objects/moduleobject.c +++ b/Objects/moduleobject.c @@ -50,6 +50,7 @@ _PyModule_IsExtension(PyObject *obj) } +#undef PyModuleDef_Init PyObject* PyModuleDef_Init(PyModuleDef* def) {