Skip to content

Commit bd9983c

Browse files
[3.13] gh-119560: Drop an Invalid Assert in PyState_FindModule() (gh-119561) (gh-119632)
The assertion was added in gh-118532 but was based on the invalid assumption that PyState_FindModule() would only be called with an already-initialized module def. I've added a test to make sure we don't make that assumption again. (cherry picked from commit 0c5ebe1) Co-authored-by: Eric Snow <ericsnowcurrently@gmail.com>
1 parent 0a4a318 commit bd9983c

File tree

4 files changed

+100
-4
lines changed

4 files changed

+100
-4
lines changed

Lib/test/test_import/__init__.py

+7
Original file line numberDiff line numberDiff line change
@@ -2887,6 +2887,13 @@ def test_with_reinit_reloaded(self):
28872887

28882888
self.assertIs(reloaded.snapshot.cached, reloaded.module)
28892889

2890+
def test_check_state_first(self):
2891+
for variant in ['', '_with_reinit', '_with_state']:
2892+
name = f'{self.NAME}{variant}_check_cache_first'
2893+
with self.subTest(name):
2894+
mod = self._load_dynamic(name, self.ORIGIN)
2895+
self.assertEqual(mod.__name__, name)
2896+
28902897
# Currently, for every single-phrase init module loaded
28912898
# in multiple interpreters, those interpreters share a
28922899
# PyModuleDef for that object, which can be a problem.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
An invalid assert in beta 1 has been removed. The assert would fail if
2+
``PyState_FindModule()`` was used in an extension module's init function
3+
before the module def had been initialized.

Modules/_testsinglephase.c

+89-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11

22
/* Testing module for single-phase initialization of extension modules
33
4-
This file contains 5 distinct modules, meaning each as its own name
4+
This file contains 8 distinct modules, meaning each as its own name
55
and its own init function (PyInit_...). The default import system will
66
only find the one matching the filename: _testsinglephase. To load the
77
others you must do so manually. For example:
@@ -14,7 +14,7 @@ spec = importlib.util.spec_from_file_location(name, filename, loader=loader)
1414
mod = importlib._bootstrap._load(spec)
1515
```
1616
17-
Here are the 5 modules:
17+
Here are the 8 modules:
1818
1919
* _testsinglephase
2020
* def: _testsinglephase_basic,
@@ -136,6 +136,32 @@ Here are the 5 modules:
136136
5. increment <global>.initialized_count
137137
* functions: see common functions below
138138
* import system: same as _testsinglephase_basic_copy
139+
* _testsinglephase_check_cache_first
140+
* def: _testsinglepahse_check_cache_first
141+
* m_name: "_testsinglephase_check_cache_first"
142+
* m_size: -1
143+
* state: none
144+
* init function:
145+
* tries PyState_FindModule() first
146+
* otherwise creates empty module
147+
* functions: none
148+
* import system: same as _testsinglephase
149+
* _testsinglephase_with_reinit_check_cache_first
150+
* def: _testsinglepahse_with_reinit_check_cache_first
151+
* m_name: "_testsinglephase_with_reinit_check_cache_first"
152+
* m_size: 0
153+
* state: none
154+
* init function: same as _testsinglephase_check_cache_first
155+
* functions: none
156+
* import system: same as _testsinglephase_with_reinit
157+
* _testsinglephase_with_state_check_cache_first
158+
* def: _testsinglepahse_with_state_check_cache_first
159+
* m_name: "_testsinglephase_with_state_check_cache_first"
160+
* m_size: 42
161+
* state: none
162+
* init function: same as _testsinglephase_check_cache_first
163+
* functions: none
164+
* import system: same as _testsinglephase_with_state
139165
140166
Module state:
141167
@@ -650,3 +676,64 @@ PyInit__testsinglephase_with_state(void)
650676
finally:
651677
return module;
652678
}
679+
680+
681+
/****************************************************/
682+
/* the _testsinglephase_*_check_cache_first modules */
683+
/****************************************************/
684+
685+
static struct PyModuleDef _testsinglephase_check_cache_first = {
686+
PyModuleDef_HEAD_INIT,
687+
.m_name = "_testsinglephase_check_cache_first",
688+
.m_doc = PyDoc_STR("Test module _testsinglephase_check_cache_first"),
689+
.m_size = -1, // no module state
690+
};
691+
692+
PyMODINIT_FUNC
693+
PyInit__testsinglephase_check_cache_first(void)
694+
{
695+
assert(_testsinglephase_check_cache_first.m_base.m_index == 0);
696+
PyObject *mod = PyState_FindModule(&_testsinglephase_check_cache_first);
697+
if (mod != NULL) {
698+
return Py_NewRef(mod);
699+
}
700+
return PyModule_Create(&_testsinglephase_check_cache_first);
701+
}
702+
703+
704+
static struct PyModuleDef _testsinglephase_with_reinit_check_cache_first = {
705+
PyModuleDef_HEAD_INIT,
706+
.m_name = "_testsinglephase_with_reinit_check_cache_first",
707+
.m_doc = PyDoc_STR("Test module _testsinglephase_with_reinit_check_cache_first"),
708+
.m_size = 0, // no module state
709+
};
710+
711+
PyMODINIT_FUNC
712+
PyInit__testsinglephase_with_reinit_check_cache_first(void)
713+
{
714+
assert(_testsinglephase_with_reinit_check_cache_first.m_base.m_index == 0);
715+
PyObject *mod = PyState_FindModule(&_testsinglephase_with_reinit_check_cache_first);
716+
if (mod != NULL) {
717+
return Py_NewRef(mod);
718+
}
719+
return PyModule_Create(&_testsinglephase_with_reinit_check_cache_first);
720+
}
721+
722+
723+
static struct PyModuleDef _testsinglephase_with_state_check_cache_first = {
724+
PyModuleDef_HEAD_INIT,
725+
.m_name = "_testsinglephase_with_state_check_cache_first",
726+
.m_doc = PyDoc_STR("Test module _testsinglephase_with_state_check_cache_first"),
727+
.m_size = 42, // not used
728+
};
729+
730+
PyMODINIT_FUNC
731+
PyInit__testsinglephase_with_state_check_cache_first(void)
732+
{
733+
assert(_testsinglephase_with_state_check_cache_first.m_base.m_index == 0);
734+
PyObject *mod = PyState_FindModule(&_testsinglephase_with_state_check_cache_first);
735+
if (mod != NULL) {
736+
return Py_NewRef(mod);
737+
}
738+
return PyModule_Create(&_testsinglephase_with_state_check_cache_first);
739+
}

Python/import.c

+1-2
Original file line numberDiff line numberDiff line change
@@ -457,7 +457,6 @@ static Py_ssize_t
457457
_get_module_index_from_def(PyModuleDef *def)
458458
{
459459
Py_ssize_t index = def->m_base.m_index;
460-
assert(index > 0);
461460
#ifndef NDEBUG
462461
struct extensions_cache_value *cached = _find_cached_def(def);
463462
assert(cached == NULL || index == _get_cached_module_index(cached));
@@ -489,7 +488,7 @@ _set_module_index(PyModuleDef *def, Py_ssize_t index)
489488
static const char *
490489
_modules_by_index_check(PyInterpreterState *interp, Py_ssize_t index)
491490
{
492-
if (index == 0) {
491+
if (index <= 0) {
493492
return "invalid module index";
494493
}
495494
if (MODULES_BY_INDEX(interp) == NULL) {

0 commit comments

Comments
 (0)