The Wayback Machine - https://web.archive.org/web/20211102051412/https://github.com/python/cpython/pull/28778/files
Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bpo-45395: Make custom frozen modules additions instead of replacements. #28778

Merged
@@ -1095,7 +1095,7 @@ We have defined the :c:type:`struct _frozen` data type, so we can get the pointe
to the table::

>>> FrozenTable = POINTER(struct_frozen)
>>> table = FrozenTable.in_dll(pythonapi, "PyImport_FrozenModules")
>>> table = FrozenTable.in_dll(pythonapi, "_PyImport_FrozenBootstrap")
>>>

Since ``table`` is a ``pointer`` to the array of ``struct_frozen`` records, we
@@ -1111,9 +1111,7 @@ hit the ``NULL`` entry::
...
_frozen_importlib 31764
_frozen_importlib_external 41499
__hello__ 161
__phello__ -161
__phello__.spam 161
zipimport 12345
>>>

The fact that standard Python has a frozen module and a frozen package
@@ -15,6 +15,9 @@ struct _module_alias {
const char *orig; /* ASCII encoded string */
};

PyAPI_DATA(const struct _frozen *) _PyImport_FrozenBootstrap;
PyAPI_DATA(const struct _frozen *) _PyImport_FrozenStdlib;
PyAPI_DATA(const struct _frozen *) _PyImport_FrozenTest;
extern const struct _module_alias * _PyImport_FrozenAliases;

#ifdef __cplusplus
@@ -56,35 +56,37 @@ class struct_frozen(Structure):
("size", c_int)]
FrozenTable = POINTER(struct_frozen)

ft = FrozenTable.in_dll(pythonapi, "PyImport_FrozenModules")
# ft is a pointer to the struct_frozen entries:
modules = []
for entry in ft:
# This is dangerous. We *can* iterate over a pointer, but
# the loop will not terminate (maybe with an access
# violation;-) because the pointer instance has no size.
if entry.name is None:
break
modname = entry.name.decode("ascii")
modules.append(modname)
with self.subTest(modname):
# Do a sanity check on entry.size and entry.code.
self.assertGreater(abs(entry.size), 10)
self.assertTrue([entry.code[i] for i in range(abs(entry.size))])
# Check the module's package-ness.
with import_helper.frozen_modules():
spec = importlib.util.find_spec(modname)
if entry.size < 0:
# It's a package.
self.assertIsNotNone(spec.submodule_search_locations)
else:
self.assertIsNone(spec.submodule_search_locations)
for group in ["Bootstrap", "Stdlib", "Test"]:
ft = FrozenTable.in_dll(pythonapi, f"_PyImport_Frozen{group}")
# ft is a pointer to the struct_frozen entries:
for entry in ft:
# This is dangerous. We *can* iterate over a pointer, but
# the loop will not terminate (maybe with an access
# violation;-) because the pointer instance has no size.
if entry.name is None:
break
modname = entry.name.decode("ascii")
modules.append(modname)
with self.subTest(modname):
# Do a sanity check on entry.size and entry.code.
self.assertGreater(abs(entry.size), 10)
self.assertTrue([entry.code[i] for i in range(abs(entry.size))])
# Check the module's package-ness.
with import_helper.frozen_modules():
spec = importlib.util.find_spec(modname)
if entry.size < 0:
# It's a package.
self.assertIsNotNone(spec.submodule_search_locations)
else:
self.assertIsNone(spec.submodule_search_locations)

with import_helper.frozen_modules():
expected = _imp._frozen_module_names()
self.maxDiff = None
self.assertEqual(modules, expected, "PyImport_FrozenModules example "
"in Doc/library/ctypes.rst may be out of date")
self.assertEqual(modules, expected,
"_PyImport_FrozenBootstrap example "
"in Doc/library/ctypes.rst may be out of date")

from ctypes import _pointer_type_cache
del _pointer_type_cache[struct_frozen]
@@ -0,0 +1,4 @@
Custom frozen modules (the array set to ``PyImport_FrozenModules``) are now
treated as additions, rather than replacing all the default frozen modules.
Frozen stdlib modules can still be disabled by setting the "code" field of
the custom array entry to NULL.
@@ -23,13 +23,16 @@
of frozen modules instead, left deliberately blank so as to avoid
unintentional import of a stale version of _frozen_importlib. */

static const struct _frozen _PyImport_FrozenModules[] = {
static const struct _frozen no_modules[] = {
{0, 0, 0} /* sentinel */
};
static const struct _module_alias aliases[] = {
{0, 0} /* sentinel */
};

const struct _frozen *_PyImport_FrozenBootstrap;
const struct _frozen *_PyImport_FrozenStdlib;
const struct _frozen *_PyImport_FrozenTest;
const struct _frozen *PyImport_FrozenModules;
const struct _module_alias *_PyImport_FrozenAliases;

@@ -188,7 +191,10 @@ main(int argc, char *argv[])
{
const char *name, *inpath, *outpath;

PyImport_FrozenModules = _PyImport_FrozenModules;
_PyImport_FrozenBootstrap = no_modules;
_PyImport_FrozenStdlib = no_modules;
_PyImport_FrozenTest = no_modules;
PyImport_FrozenModules = NULL;
_PyImport_FrozenAliases = aliases;

if (argc != 4) {
@@ -8,6 +8,7 @@
#include <Python.h>
#include "pycore_initconfig.h" // _PyConfig_InitCompatConfig()
#include "pycore_runtime.h" // _PyRuntime
#include "pycore_import.h" // _PyImport_FrozenBootstrap
#include <Python.h>
#include <inttypes.h>
#include <stdio.h>
@@ -1732,7 +1733,7 @@
if (rawval == NULL) {
wcscpy(optval, L"frozen_modules");
}
else if (swprintf(optval, 100, L"frozen_modules=%s", rawval) < 0) {

Check warning on line 1736 in Programs/_testembed.c

GitHub Actions / Windows (x64)

Programs/_testembed.c#L1736

'swprintf' : format string '%s' requires an argument of type 'unsigned short *', but variadic argument 1 has type 'const char *' [D:\a\cpython\cpython\PCbuild\_testembed.vcxproj]

Check warning on line 1736 in Programs/_testembed.c

GitHub Actions / Windows (x64)

Programs/_testembed.c#L1736

'swprintf' : format string '%s' requires an argument of type 'unsigned short *', but variadic argument 1 has type 'const char *' [D:\a\cpython\cpython\PCbuild\_testembed.vcxproj]
error("rawval is too long");
return -1;
}
@@ -1804,30 +1805,10 @@

static int test_frozenmain(void)
{
// Get "_frozen_importlib" and "_frozen_importlib_external"
// from PyImport_FrozenModules
const struct _frozen *importlib = NULL, *importlib_external = NULL;
for (const struct _frozen *mod = PyImport_FrozenModules; mod->name != NULL; mod++) {
if (strcmp(mod->name, "_frozen_importlib") == 0) {
importlib = mod;
}
else if (strcmp(mod->name, "_frozen_importlib_external") == 0) {
importlib_external = mod;
}
}
if (importlib == NULL || importlib_external == NULL) {
error("cannot find frozen importlib and importlib_external");
return 1;
}

static struct _frozen frozen_modules[4] = {
{0, 0, 0}, // importlib
{0, 0, 0}, // importlib_external
{"__main__", M_test_frozenmain, sizeof(M_test_frozenmain)},
{0, 0, 0} // sentinel
};
frozen_modules[0] = *importlib;
frozen_modules[1] = *importlib_external;

char* argv[] = {
"./argv0",
@@ -1846,7 +1827,12 @@
static int list_frozen(void)
{
const struct _frozen *p;
for (p = PyImport_FrozenModules; ; p++) {
for (p = _PyImport_FrozenBootstrap; ; p++) {
if (p->name == NULL)
break;
printf("%s\n", p->name);
}
for (p = _PyImport_FrozenStdlib; ; p++) {
if (p->name == NULL)
break;
printf("%s\n", p->name);
@@ -63,14 +63,15 @@

/* Note that a negative size indicates a package. */

static const struct _frozen _PyImport_FrozenModules[] = {
/* import system */
static const struct _frozen bootstrap_modules[] = {
{"_frozen_importlib", _Py_M__importlib__bootstrap,
(int)sizeof(_Py_M__importlib__bootstrap)},
{"_frozen_importlib_external", _Py_M__importlib__bootstrap_external,
(int)sizeof(_Py_M__importlib__bootstrap_external)},
{"zipimport", _Py_M__zipimport, (int)sizeof(_Py_M__zipimport)},

{0, 0, 0} /* bootstrap sentinel */
};
static const struct _frozen stdlib_modules[] = {
/* stdlib - startup, without site (python -S) */
{"abc", _Py_M__abc, (int)sizeof(_Py_M__abc)},
{"codecs", _Py_M__codecs, (int)sizeof(_Py_M__codecs)},
@@ -87,8 +88,9 @@ static const struct _frozen _PyImport_FrozenModules[] = {
{"os", _Py_M__os, (int)sizeof(_Py_M__os)},
{"site", _Py_M__site, (int)sizeof(_Py_M__site)},
{"stat", _Py_M__stat, (int)sizeof(_Py_M__stat)},

/* Test module */
{0, 0, 0} /* stdlib sentinel */
};
static const struct _frozen test_modules[] = {
{"__hello__", _Py_M____hello__, (int)sizeof(_Py_M____hello__)},
{"__hello_alias__", _Py_M____hello__, (int)sizeof(_Py_M____hello__)},
{"__phello_alias__", _Py_M____hello__, -(int)sizeof(_Py_M____hello__)},
@@ -103,8 +105,11 @@ static const struct _frozen _PyImport_FrozenModules[] = {
{"__phello__.spam", _Py_M____phello___spam,
(int)sizeof(_Py_M____phello___spam)},
{"__hello_only__", _Py_M__frozen_only, (int)sizeof(_Py_M__frozen_only)},
{0, 0, 0} /* modules sentinel */
{0, 0, 0} /* test sentinel */
};
const struct _frozen *_PyImport_FrozenBootstrap = bootstrap_modules;
const struct _frozen *_PyImport_FrozenStdlib = stdlib_modules;
const struct _frozen *_PyImport_FrozenTest = test_modules;

static const struct _module_alias aliases[] = {
{"_frozen_importlib", "importlib._bootstrap"},
@@ -124,4 +129,4 @@ const struct _module_alias *_PyImport_FrozenAliases = aliases;
/* Embedding apps may change this pointer to point to their favorite
collection of frozen modules: */

const struct _frozen *PyImport_FrozenModules = _PyImport_FrozenModules;
const struct _frozen *PyImport_FrozenModules = NULL;