gh-117953: Track Extra Details in Global Extensions Cache (gh-118532)

We have only been tracking each module's PyModuleDef.  However, there are some problems with that.  For example, in some cases we load single-phase init extension modules from def->m_base.m_init or def->m_base.m_copy, but if multiple modules share a def then we can end up with unexpected behavior.

With this change, we track the following:

* PyModuleDef (same as before)
* for some modules, its init function or a copy of its __dict__, but specific to that module
* whether it is a builtin/core module or a "dynamic" extension
* the interpreter (ID) that owns the cached __dict__ (only if cached)

This also makes it easier to remember the module's kind (e.g. single-phase init) and if loading it previously failed, which I'm doing separately.
This commit is contained in:
Eric Snow 2024-05-04 15:24:02 -06:00 committed by GitHub
parent 978fba58ae
commit 291cfa454b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 577 additions and 137 deletions

View file

@ -22,6 +22,11 @@ typedef enum ext_module_kind {
_Py_ext_module_kind_INVALID = 3, _Py_ext_module_kind_INVALID = 3,
} _Py_ext_module_kind; } _Py_ext_module_kind;
typedef enum ext_module_origin {
_Py_ext_module_origin_CORE = 1,
_Py_ext_module_origin_BUILTIN = 2,
_Py_ext_module_origin_DYNAMIC = 3,
} _Py_ext_module_origin;
/* Input for loading an extension module. */ /* Input for loading an extension module. */
struct _Py_ext_module_loader_info { struct _Py_ext_module_loader_info {
@ -34,6 +39,7 @@ struct _Py_ext_module_loader_info {
/* path is always a borrowed ref of name or filename, /* path is always a borrowed ref of name or filename,
* depending on if it's builtin or not. */ * depending on if it's builtin or not. */
PyObject *path; PyObject *path;
_Py_ext_module_origin origin;
const char *hook_prefix; const char *hook_prefix;
const char *newcontext; const char *newcontext;
}; };
@ -42,7 +48,11 @@ extern void _Py_ext_module_loader_info_clear(
extern int _Py_ext_module_loader_info_init( extern int _Py_ext_module_loader_info_init(
struct _Py_ext_module_loader_info *info, struct _Py_ext_module_loader_info *info,
PyObject *name, PyObject *name,
PyObject *filename); PyObject *filename,
_Py_ext_module_origin origin);
extern int _Py_ext_module_loader_info_init_for_core(
struct _Py_ext_module_loader_info *p_info,
PyObject *name);
extern int _Py_ext_module_loader_info_init_for_builtin( extern int _Py_ext_module_loader_info_init_for_builtin(
struct _Py_ext_module_loader_info *p_info, struct _Py_ext_module_loader_info *p_info,
PyObject *name); PyObject *name);

File diff suppressed because it is too large Load diff

View file

@ -111,9 +111,12 @@ _Py_ext_module_loader_info_clear(struct _Py_ext_module_loader_info *info)
int int
_Py_ext_module_loader_info_init(struct _Py_ext_module_loader_info *p_info, _Py_ext_module_loader_info_init(struct _Py_ext_module_loader_info *p_info,
PyObject *name, PyObject *filename) PyObject *name, PyObject *filename,
_Py_ext_module_origin origin)
{ {
struct _Py_ext_module_loader_info info = {0}; struct _Py_ext_module_loader_info info = {
.origin=origin,
};
assert(name != NULL); assert(name != NULL);
if (!PyUnicode_Check(name)) { if (!PyUnicode_Check(name)) {
@ -183,12 +186,25 @@ _Py_ext_module_loader_info_init_for_builtin(
.name_encoded=name_encoded, .name_encoded=name_encoded,
/* We won't need filename. */ /* We won't need filename. */
.path=name, .path=name,
.origin=_Py_ext_module_origin_BUILTIN,
.hook_prefix=ascii_only_prefix, .hook_prefix=ascii_only_prefix,
.newcontext=NULL, .newcontext=NULL,
}; };
return 0; return 0;
} }
int
_Py_ext_module_loader_info_init_for_core(
struct _Py_ext_module_loader_info *info,
PyObject *name)
{
if (_Py_ext_module_loader_info_init_for_builtin(info, name) < 0) {
return -1;
}
info->origin = _Py_ext_module_origin_CORE;
return 0;
}
int int
_Py_ext_module_loader_info_init_from_spec( _Py_ext_module_loader_info_init_from_spec(
struct _Py_ext_module_loader_info *p_info, struct _Py_ext_module_loader_info *p_info,
@ -203,7 +219,9 @@ _Py_ext_module_loader_info_init_from_spec(
Py_DECREF(name); Py_DECREF(name);
return -1; return -1;
} }
int err = _Py_ext_module_loader_info_init(p_info, name, filename); /* We could also accommodate builtin modules here without much trouble. */
_Py_ext_module_origin origin = _Py_ext_module_origin_DYNAMIC;
int err = _Py_ext_module_loader_info_init(p_info, name, filename, origin);
Py_DECREF(name); Py_DECREF(name);
Py_DECREF(filename); Py_DECREF(filename);
return err; return err;