'-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):
}
+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)
{
_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);
}