Skip to content

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

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

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 2 additions & 4 deletions Doc/library/ctypes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
3 changes: 3 additions & 0 deletions Include/internal/pycore_import.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
50 changes: 26 additions & 24 deletions Lib/ctypes/test/test_values.py
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down
Original file line number Diff line number Diff line change
@@ -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.
10 changes: 8 additions & 2 deletions Programs/_freeze_module.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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) {
Expand Down
28 changes: 7 additions & 21 deletions Programs/_testembed.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -1804,30 +1805,10 @@ static int test_unicode_id_init(void)

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",
Expand All @@ -1846,7 +1827,12 @@ static int test_frozenmain(void)
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);
Expand Down
19 changes: 12 additions & 7 deletions Python/frozen.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)},
Expand All @@ -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__)},
Expand All @@ -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"},
Expand All @@ -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;
Loading