Skip to content

Commit cb2ef8b

Browse files
authored
gh-99578: Fix refleak in _imp.create_builtin() (#99642)
Fix a reference bug in _imp.create_builtin() after the creation of the first sub-interpreter for modules "builtins" and "sys".
1 parent 1cae31d commit cb2ef8b

File tree

3 files changed

+35
-1
lines changed

3 files changed

+35
-1
lines changed

Diff for: Lib/test/test_imp.py

+30
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import gc
12
import importlib
23
import importlib.util
34
import os
@@ -413,6 +414,35 @@ def __init__(self, name):
413414
bltin = create_builtin(spec)
414415
self.assertEqual(bltin, builtins)
415416

417+
@support.cpython_only
418+
def test_create_builtin_subinterp(self):
419+
# gh-99578: create_builtin() behavior changes after the creation of the
420+
# first sub-interpreter. Test both code paths, before and after the
421+
# creation of a sub-interpreter. Previously, create_builtin() had
422+
# a reference leak after the creation of the first sub-interpreter.
423+
424+
import builtins
425+
create_builtin = support.get_attribute(_imp, "create_builtin")
426+
class Spec:
427+
name = "builtins"
428+
spec = Spec()
429+
430+
def check_get_builtins():
431+
refcnt = sys.getrefcount(builtins)
432+
mod = _imp.create_builtin(spec)
433+
self.assertIs(mod, builtins)
434+
self.assertEqual(sys.getrefcount(builtins), refcnt + 1)
435+
# Check that a GC collection doesn't crash
436+
gc.collect()
437+
438+
check_get_builtins()
439+
440+
ret = support.run_in_subinterp("import builtins")
441+
self.assertEqual(ret, 0)
442+
443+
check_get_builtins()
444+
445+
416446
class ReloadTests(unittest.TestCase):
417447

418448
"""Very basic tests to make sure that imp.reload() operates just like
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Fix a reference bug in :func:`_imp.create_builtin()` after the creation of the
2+
first sub-interpreter for modules ``builtins`` and ``sys``. Patch by Victor
3+
Stinner.

Diff for: Python/import.c

+2-1
Original file line numberDiff line numberDiff line change
@@ -1035,7 +1035,8 @@ create_builtin(PyThreadState *tstate, PyObject *name, PyObject *spec)
10351035
if (_PyUnicode_EqualToASCIIString(name, p->name)) {
10361036
if (p->initfunc == NULL) {
10371037
/* Cannot re-init internal module ("sys" or "builtins") */
1038-
return PyImport_AddModuleObject(name);
1038+
mod = PyImport_AddModuleObject(name);
1039+
return Py_XNewRef(mod);
10391040
}
10401041
mod = _PyImport_InitFunc_TrampolineCall(*p->initfunc);
10411042
if (mod == NULL) {

0 commit comments

Comments
 (0)