[3.10] gh-94207: Fix struct module leak (GH-94239) (GH-94266)

* gh-94207: Fix struct module leak (GH-94239)

Make _struct.Struct a GC type

This fixes a memory leak in the _struct module, where as soon
as a Struct object is stored in the cache, there's a cycle from
the _struct module to the cache to Struct objects to the Struct
type back to the module. If _struct.Struct is not gc-tracked, that
cycle is never collected.

This PR makes _struct.Struct GC-tracked, and adds a regression test.
(cherry picked from commit 6b865349aa)

Co-authored-by: Mark Dickinson <dickinsm@gmail.com>
This commit is contained in:
Miss Islington (bot) 2022-06-25 08:05:06 -07:00 committed by GitHub
parent 14943829a8
commit 86e49a5026
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 40 additions and 2 deletions

View file

@ -1,12 +1,15 @@
from collections import abc
import array
import gc
import math
import operator
import unittest
import struct
import sys
import weakref
from test import support
from test.support import import_helper
from test.support.script_helper import assert_python_ok
ISBIGENDIAN = sys.byteorder == "big"
@ -671,6 +674,21 @@ class StructTest(unittest.TestCase):
self.assertIn(b"Exception ignored in:", stderr)
self.assertIn(b"C.__del__", stderr)
def test__struct_reference_cycle_cleaned_up(self):
# Regression test for python/cpython#94207.
# When we create a new struct module, trigger use of its cache,
# and then delete it ...
_struct_module = import_helper.import_fresh_module("_struct")
module_ref = weakref.ref(_struct_module)
_struct_module.calcsize("b")
del _struct_module
# Then the module should have been garbage collected.
gc.collect()
self.assertIsNone(
module_ref(), "_struct module was not garbage collected")
def test_issue35714(self):
# Embedded null characters should not be allowed in format strings.
for s in '\0', '2\0i', b'\0':