diff options
-rw-r--r-- | Include/internal/pycore_unicodeobject.h | 1 | ||||
-rw-r--r-- | Lib/__hello__.py | 9 | ||||
-rw-r--r-- | Lib/test/test_embed.py | 41 | ||||
-rw-r--r-- | Objects/unicodeobject.c | 44 | ||||
-rw-r--r-- | Tools/scripts/deepfreeze.py | 1 |
5 files changed, 78 insertions, 18 deletions
diff --git a/Include/internal/pycore_unicodeobject.h b/Include/internal/pycore_unicodeobject.h index 4394ce9..c7f0605 100644 --- a/Include/internal/pycore_unicodeobject.h +++ b/Include/internal/pycore_unicodeobject.h @@ -18,6 +18,7 @@ extern PyStatus _PyUnicode_InitGlobalObjects(PyInterpreterState *); extern PyStatus _PyUnicode_InitTypes(PyInterpreterState *); extern void _PyUnicode_Fini(PyInterpreterState *); extern void _PyUnicode_FiniTypes(PyInterpreterState *); +extern void _PyStaticUnicode_Dealloc(PyObject *); /* other API */ diff --git a/Lib/__hello__.py b/Lib/__hello__.py index d37bd27..c09d6a4 100644 --- a/Lib/__hello__.py +++ b/Lib/__hello__.py @@ -1,5 +1,14 @@ initialized = True +class TestFrozenUtf8_1: + """\u00b6""" + +class TestFrozenUtf8_2: + """\u03c0""" + +class TestFrozenUtf8_4: + """\U0001f600""" + def main(): print("Hello world!") diff --git a/Lib/test/test_embed.py b/Lib/test/test_embed.py index 80b9674..f0c88de 100644 --- a/Lib/test/test_embed.py +++ b/Lib/test/test_embed.py @@ -1645,24 +1645,29 @@ class MiscTests(EmbeddingTestsMixin, unittest.TestCase): '-X showrefcount requires a Python debug build') def test_no_memleak(self): # bpo-1635741: Python must release all memory at exit - cmd = [sys.executable, "-I", "-X", "showrefcount", "-c", "pass"] - proc = subprocess.run(cmd, - stdout=subprocess.PIPE, - stderr=subprocess.STDOUT, - text=True) - self.assertEqual(proc.returncode, 0) - out = proc.stdout.rstrip() - match = re.match(r'^\[(-?\d+) refs, (-?\d+) blocks\]', out) - if not match: - self.fail(f"unexpected output: {out!a}") - refs = int(match.group(1)) - blocks = int(match.group(2)) - self.assertEqual(refs, 0, out) - if not MS_WINDOWS: - self.assertEqual(blocks, 0, out) - else: - # bpo-46857: on Windows, Python still leaks 1 memory block at exit - self.assertIn(blocks, (0, 1), out) + tests = ( + ('off', 'pass'), + ('on', 'pass'), + ('off', 'import __hello__'), + ('on', 'import __hello__'), + ) + for flag, stmt in tests: + xopt = f"frozen_modules={flag}" + cmd = [sys.executable, "-I", "-X", "showrefcount", "-X", xopt, "-c", stmt] + proc = subprocess.run(cmd, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + text=True) + self.assertEqual(proc.returncode, 0) + out = proc.stdout.rstrip() + match = re.match(r'^\[(-?\d+) refs, (-?\d+) blocks\]', out) + if not match: + self.fail(f"unexpected output: {out!a}") + refs = int(match.group(1)) + blocks = int(match.group(2)) + with self.subTest(frozen_modules=flag, stmt=stmt): + self.assertEqual(refs, 0, out) + self.assertEqual(blocks, 0, out) class StdPrinterTests(EmbeddingTestsMixin, unittest.TestCase): diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index 5dfe6e1..ce3ebce 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -16057,6 +16057,35 @@ _PyUnicode_FiniTypes(PyInterpreterState *interp) } +static void unicode_static_dealloc(PyObject *op) +{ + PyASCIIObject* ascii = (PyASCIIObject*)op; + + assert(ascii->state.compact); + + if (ascii->state.ascii) { + if (ascii->wstr) { + PyObject_Free(ascii->wstr); + ascii->wstr = NULL; + } + } + else { + PyCompactUnicodeObject* compact = (PyCompactUnicodeObject*)op; + void* data = (void*)(compact + 1); + if (ascii->wstr && ascii->wstr != data) { + PyObject_Free(ascii->wstr); + ascii->wstr = NULL; + compact->wstr_length = 0; + } + if (compact->utf8) { + PyObject_Free(compact->utf8); + compact->utf8 = NULL; + compact->utf8_length = 0; + } + } +} + + void _PyUnicode_Fini(PyInterpreterState *interp) { @@ -16070,6 +16099,21 @@ _PyUnicode_Fini(PyInterpreterState *interp) _PyUnicode_FiniEncodings(&state->fs_codec); unicode_clear_identifiers(state); + + // Clear the single character singletons + for (int i = 0; i < 128; i++) { + unicode_static_dealloc((PyObject*)&_Py_SINGLETON(strings).ascii[i]); + } + for (int i = 0; i < 128; i++) { + unicode_static_dealloc((PyObject*)&_Py_SINGLETON(strings).latin1[i]); + } +} + + +void +_PyStaticUnicode_Dealloc(PyObject *op) +{ + unicode_static_dealloc(op); } diff --git a/Tools/scripts/deepfreeze.py b/Tools/scripts/deepfreeze.py index d208258..1831c15 100644 --- a/Tools/scripts/deepfreeze.py +++ b/Tools/scripts/deepfreeze.py @@ -185,6 +185,7 @@ class Printer: else: self.write("PyCompactUnicodeObject _compact;") self.write(f"{datatype} _data[{len(s)+1}];") + self.deallocs.append(f"_PyStaticUnicode_Dealloc((PyObject *)&{name});") with self.block(f"{name} =", ";"): if ascii: with self.block("._ascii =", ","): |