Skip to content

Commit 525b5f1

Browse files
encukoubefeleme
authored andcommitted
00477: Raise an error when importing stdlib modules compiled for a different Python version
This is a downstream workaround "implementing" python#137212 - the mechanism for the check exists in Python 3.15+, where it needs to be added to the standard library modules. In Fedora, we need it also in previous Python versions, as we experience segmentation fault when importing stdlib modules after update while Python is running. _curses, _tkinter, _tracemalloc and readline are not calling PyModuleDef_Init, which is modified with this patch, hence they need a direct call to the check function. Co-Authored-By: Karolina Surma <ksurma@redhat.com>
1 parent 2324002 commit 525b5f1

7 files changed

Lines changed: 71 additions & 0 deletions

File tree

‎Include/moduleobject.h‎

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,49 @@ struct PyModuleDef {
116116
freefunc m_free;
117117
};
118118

119+
#if defined(_PyHack_check_version_on_modinit) && defined(Py_BUILD_CORE)
120+
/* The mechanism for the check has been implemented on Python 3.15+:
121+
* https://github.com/python/cpython/pull/137212.
122+
* In Fedora, we need this in older Pythons too:
123+
* if somebody attempts to import a module compiled for a different Python version,
124+
* instead of segmentation fault a meaningful error is raised.
125+
*/
126+
PyAPI_DATA(const unsigned long) Py_Version;
127+
128+
static inline int
129+
_PyHack_CheckInternalAPIVersion(const char *mod_name)
130+
{
131+
if (PY_VERSION_HEX != Py_Version) {
132+
PyErr_Format(
133+
PyExc_ImportError,
134+
"internal Python C API version mismatch: "
135+
"module %s compiled with %lu.%lu.%lu; "
136+
"runtime version is %lu.%lu.%lu",
137+
mod_name,
138+
(const unsigned long)((PY_VERSION_HEX >> 24) & 0xFF),
139+
(const unsigned long)((PY_VERSION_HEX >> 16) & 0xFF),
140+
(const unsigned long)((PY_VERSION_HEX >> 8) & 0xFF),
141+
(const unsigned long)((Py_Version >> 24) & 0xFF),
142+
(const unsigned long)((Py_Version >> 16) & 0xFF),
143+
(const unsigned long)((Py_Version >> 8) & 0xFF)
144+
);
145+
return -1;
146+
}
147+
return 0;
148+
}
149+
150+
static inline PyObject *
151+
PyModuleDef_Init_with_check(PyModuleDef *def)
152+
{
153+
if (_PyHack_CheckInternalAPIVersion(def->m_name) < 0) {
154+
return NULL;
155+
}
156+
return PyModuleDef_Init(def);
157+
}
158+
159+
#define PyModuleDef_Init PyModuleDef_Init_with_check
160+
#endif
161+
119162
#ifdef __cplusplus
120163
}
121164
#endif

‎Makefile.pre.in‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3159,3 +3159,6 @@ MODULE__MULTIBYTECODEC_DEPS=$(srcdir)/Modules/cjkcodecs/multibytecodec.h
31593159
# Local Variables:
31603160
# mode: makefile
31613161
# End:
3162+
3163+
# Fedora-specific, downstream only
3164+
PY_STDMODULE_CFLAGS += -D_PyHack_check_version_on_modinit=1

‎Modules/_cursesmodule.c‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5011,6 +5011,12 @@ curses_destructor(PyObject *op)
50115011
PyMODINIT_FUNC
50125012
PyInit__curses(void)
50135013
{
5014+
#ifdef _PyHack_check_version_on_modinit
5015+
if (_PyHack_CheckInternalAPIVersion("_curses") < 0) {
5016+
return NULL;
5017+
}
5018+
#endif
5019+
50145020
PyObject *m, *d, *v, *c_api_object;
50155021

50165022
/* Initialize object type */

‎Modules/_tkinter.c‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3499,6 +3499,12 @@ static struct PyModuleDef _tkintermodule = {
34993499
PyMODINIT_FUNC
35003500
PyInit__tkinter(void)
35013501
{
3502+
#ifdef _PyHack_check_version_on_modinit
3503+
if (_PyHack_CheckInternalAPIVersion("_tkinter") < 0) {
3504+
return NULL;
3505+
}
3506+
#endif
3507+
35023508
PyObject *m, *uexe, *cexe;
35033509

35043510
tcl_lock = PyThread_allocate_lock();

‎Modules/_tracemalloc.c‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,12 @@ static struct PyModuleDef module_def = {
215215
PyMODINIT_FUNC
216216
PyInit__tracemalloc(void)
217217
{
218+
#ifdef _PyHack_check_version_on_modinit
219+
if (_PyHack_CheckInternalAPIVersion("_tracemalloc") < 0) {
220+
return NULL;
221+
}
222+
#endif
223+
218224
PyObject *m;
219225
m = PyModule_Create(&module_def);
220226
if (m == NULL)

‎Modules/readline.c‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1548,6 +1548,12 @@ static struct PyModuleDef readlinemodule = {
15481548
PyMODINIT_FUNC
15491549
PyInit_readline(void)
15501550
{
1551+
#ifdef _PyHack_check_version_on_modinit
1552+
if (_PyHack_CheckInternalAPIVersion("readline") < 0) {
1553+
return NULL;
1554+
}
1555+
#endif
1556+
15511557
const char *backend = "readline";
15521558
PyObject *m;
15531559
readlinestate *mod_state;

‎Objects/moduleobject.c‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ _PyModule_IsExtension(PyObject *obj)
4343
}
4444

4545

46+
#undef PyModuleDef_Init
4647
PyObject*
4748
PyModuleDef_Init(PyModuleDef* def)
4849
{

0 commit comments

Comments
 (0)