bpo-38076 Clear the interpreter state only after clearing module glob… · python/cpython@4590f72

5 files changed

lines changed

Original file line numberDiff line numberDiff line change

@@ -3683,7 +3683,7 @@ def _to_memoryview(buf):

36833683
36843684

class CTextIOWrapperTest(TextIOWrapperTest):

36853685

io = io

3686-

shutdown_error = "RuntimeError: could not find io module state"

3686+

shutdown_error = "LookupError: unknown encoding: ascii"

36873687
36883688

def test_initialization(self):

36893689

r = self.BytesIO(b"\xc3\xa9\n\n")

Original file line numberDiff line numberDiff line change

@@ -7,6 +7,7 @@

77

import sys

88
99

from test import support

10+

from test.support.script_helper import assert_python_ok

1011
1112

ISBIGENDIAN = sys.byteorder == "big"

1213

@@ -652,6 +653,23 @@ def test_format_attr(self):

652653

s2 = struct.Struct(s.format.encode())

653654

self.assertEqual(s2.format, s.format)

654655
656+

def test_struct_cleans_up_at_runtime_shutdown(self):

657+

code = """if 1:

658+

import struct

659+
660+

class C:

661+

def __init__(self):

662+

self.pack = struct.pack

663+

def __del__(self):

664+

self.pack('I', -42)

665+
666+

struct.x = C()

667+

"""

668+

rc, stdout, stderr = assert_python_ok("-c", code)

669+

self.assertEqual(rc, 0)

670+

self.assertEqual(stdout.rstrip(), b"")

671+

self.assertIn(b"Exception ignored in:", stderr)

672+

self.assertIn(b"C.__del__", stderr)

655673
656674

class UnpackIteratorTest(unittest.TestCase):

657675

"""

Original file line numberDiff line numberDiff line change

@@ -855,6 +855,23 @@ def __del__(self, sys=sys):

855855

self.assertIn(b'sys.flags', out[0])

856856

self.assertIn(b'sys.float_info', out[1])

857857
858+

def test_sys_ignores_cleaning_up_user_data(self):

859+

code = """if 1:

860+

import struct, sys

861+
862+

class C:

863+

def __init__(self):

864+

self.pack = struct.pack

865+

def __del__(self):

866+

self.pack('I', -42)

867+
868+

sys.x = C()

869+

"""

870+

rc, stdout, stderr = assert_python_ok('-c', code)

871+

self.assertEqual(rc, 0)

872+

self.assertEqual(stdout.rstrip(), b"")

873+

self.assertEqual(stderr.rstrip(), b"")

874+
858875

@unittest.skipUnless(hasattr(sys, 'getandroidapilevel'),

859876

'need sys.getandroidapilevel()')

860877

def test_getandroidapilevel(self):

Original file line numberDiff line numberDiff line change

@@ -0,0 +1,2 @@

1+

Fix to clear the interpreter state only after clearing module globals to

2+

guarantee module state access from C Extensions during runtime destruction

Original file line numberDiff line numberDiff line change

@@ -568,8 +568,6 @@ _PyImport_Cleanup(PyThreadState *tstate)

568568

_PyErr_Clear(tstate);

569569

}

570570

Py_XDECREF(dict);

571-

/* Clear module dict copies stored in the interpreter state */

572-

_PyInterpreterState_ClearModules(interp);

573571

/* Collect references */

574572

_PyGC_CollectNoFail();

575573

/* Dump GC stats before it's too late, since it uses the warnings

@@ -621,6 +619,9 @@ _PyImport_Cleanup(PyThreadState *tstate)

621619

}

622620

_PyModule_ClearDict(interp->builtins);

623621
622+

/* Clear module dict copies stored in the interpreter state */

623+

_PyInterpreterState_ClearModules(interp);

624+
624625

/* Clear and delete the modules directory. Actual modules will

625626

still be there only if imported during the execution of some

626627

destructor. */