From 4dc746310bd37ad6b381f9176acd167d445f4385 Mon Sep 17 00:00:00 2001 From: Kumar Aditya <59607654+kumaraditya303@users.noreply.github.com> Date: Thu, 24 Feb 2022 22:24:06 +0530 Subject: [PATCH] bpo-46430: Fix memory leak in interned strings of deep-frozen modules (GH-31549) --- Include/internal/pycore_pylifecycle.h | 2 +- .../2022-02-24-07-33-29.bpo-46430.c91TAg.rst | 1 + Programs/_bootstrap_python.c | 8 ++++++-- Programs/_freeze_module.c | 4 ++++ Python/pylifecycle.c | 6 ++++-- Tools/scripts/deepfreeze.py | 6 +++++- 6 files changed, 21 insertions(+), 6 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2022-02-24-07-33-29.bpo-46430.c91TAg.rst diff --git a/Include/internal/pycore_pylifecycle.h b/Include/internal/pycore_pylifecycle.h index 439bc5b470b..deac6ee3d3f 100644 --- a/Include/internal/pycore_pylifecycle.h +++ b/Include/internal/pycore_pylifecycle.h @@ -65,7 +65,7 @@ extern PyStatus _Py_HashRandomization_Init(const PyConfig *); extern PyStatus _PyImportZip_Init(PyThreadState *tstate); extern PyStatus _PyGC_Init(PyInterpreterState *interp); extern PyStatus _PyAtExit_Init(PyInterpreterState *interp); - +extern void _Py_Deepfreeze_Init(void); /* Various internal finalizers */ diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-02-24-07-33-29.bpo-46430.c91TAg.rst b/Misc/NEWS.d/next/Core and Builtins/2022-02-24-07-33-29.bpo-46430.c91TAg.rst new file mode 100644 index 00000000000..0ae128ba7b7 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-02-24-07-33-29.bpo-46430.c91TAg.rst @@ -0,0 +1 @@ +Fix memory leak in interned strings of deep-frozen modules. diff --git a/Programs/_bootstrap_python.c b/Programs/_bootstrap_python.c index f4d0167b62e..75d455ca179 100644 --- a/Programs/_bootstrap_python.c +++ b/Programs/_bootstrap_python.c @@ -14,9 +14,13 @@ #include "Python/frozen_modules/importlib._bootstrap_external.h" /* End includes */ -/* Empty finalizer for deepfrozen modules*/ +/* Empty initializer for deepfrozen modules */ +void _Py_Deepfreeze_Init(void) +{ +} +/* Empty finalizer for deepfrozen modules */ void -_Py_Deepfreeze_Fini(void) +_Py_Deepfreeze_Fini(void) { } diff --git a/Programs/_freeze_module.c b/Programs/_freeze_module.c index 99a1d4dfc26..d5a236a0c63 100644 --- a/Programs/_freeze_module.c +++ b/Programs/_freeze_module.c @@ -22,6 +22,10 @@ #include #endif +/* Empty initializer for deepfrozen modules */ +void _Py_Deepfreeze_Init(void) +{ +} /* Empty finalizer for deepfrozen modules */ void _Py_Deepfreeze_Fini(void) diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index b6310c9aeb8..9dd769a0e87 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -754,7 +754,6 @@ pycore_init_types(PyInterpreterState *interp) if (_PyStatus_EXCEPTION(status)) { return status; } - return _PyStatus_OK(); } @@ -827,7 +826,10 @@ pycore_interp_init(PyThreadState *tstate) if (_PyStatus_EXCEPTION(status)) { return status; } - + // Intern strings in deep-frozen modules first so that others + // can use it instead of creating a heap allocated string. + _Py_Deepfreeze_Init(); + status = pycore_init_types(interp); if (_PyStatus_EXCEPTION(status)) { goto done; diff --git a/Tools/scripts/deepfreeze.py b/Tools/scripts/deepfreeze.py index 0edf3af71d9..b62be3713fe 100644 --- a/Tools/scripts/deepfreeze.py +++ b/Tools/scripts/deepfreeze.py @@ -110,6 +110,7 @@ def __init__(self, file: TextIO) -> None: self.hits, self.misses = 0, 0 self.patchups: list[str] = [] self.deallocs: list[str] = [] + self.interns: list[str] = [] self.write('#include "Python.h"') self.write('#include "internal/pycore_gc.h"') self.write('#include "internal/pycore_code.h"') @@ -279,7 +280,7 @@ def generate_code(self, name: str, code: types.CodeType) -> str: self.write(f".co_cellvars = {co_cellvars},") self.write(f".co_freevars = {co_freevars},") self.deallocs.append(f"_PyStaticCode_Dealloc(&{name});") - self.patchups.append(f"_PyStaticCode_InternStrings(&{name});") + self.interns.append(f"_PyStaticCode_InternStrings(&{name});") return f"& {name}.ob_base" def generate_tuple(self, name: str, t: Tuple[object, ...]) -> str: @@ -446,6 +447,9 @@ def generate(args: list[str], output: TextIO) -> None: with printer.block(f"void\n_Py_Deepfreeze_Fini(void)"): for p in printer.deallocs: printer.write(p) + with printer.block(f"void\n_Py_Deepfreeze_Init(void)"): + for p in printer.interns: + printer.write(p) if verbose: print(f"Cache hits: {printer.hits}, misses: {printer.misses}")