Close #15386: There was a loophole that meant importlib.machinery and imp would sometimes reference an uninitialised copy of importlib._bootstrap

This commit is contained in:
Nick Coghlan 2012-07-20 23:40:09 +10:00
parent 818b1186f9
commit be7e49fd82
5 changed files with 27 additions and 5 deletions

View file

@ -2,14 +2,21 @@
__all__ = ['__import__', 'import_module', 'invalidate_caches'] __all__ = ['__import__', 'import_module', 'invalidate_caches']
# Bootstrap help ##################################################### # Bootstrap help #####################################################
import imp
# Until bootstrapping is complete, DO NOT import any modules that attempt
# to import importlib._bootstrap (directly or indirectly). Since this
# partially initialised package would be present in sys.modules, those
# modules would get an uninitialised copy of the source version, instead
# of a fully initialised version (either the frozen one or the one
# initialised below if the frozen one is not available).
import _imp # Just the builtin component, NOT the full Python module
import sys import sys
try: try:
import _frozen_importlib as _bootstrap import _frozen_importlib as _bootstrap
except ImportError: except ImportError:
from . import _bootstrap from . import _bootstrap
_bootstrap._setup(sys, imp) _bootstrap._setup(sys, _imp)
else: else:
# importlib._bootstrap is the built-in import, ensure we don't create # importlib._bootstrap is the built-in import, ensure we don't create
# a second copy of the module. # a second copy of the module.
@ -22,6 +29,8 @@ else:
_w_long = _bootstrap._w_long _w_long = _bootstrap._w_long
_r_long = _bootstrap._r_long _r_long = _bootstrap._r_long
# Fully bootstrapped at this point, import whatever you like, circular
# dependencies and startup overhead minimisation permitting :)
# Public API ######################################################### # Public API #########################################################

View file

@ -2,8 +2,8 @@
import os import os
import sys import sys
import imp
import importlib import importlib
import imp
import os.path import os.path
from warnings import warn from warnings import warn
from types import ModuleType from types import ModuleType

View file

@ -12,8 +12,8 @@ importers when locating support scripts as well as when importing modules.
import os import os
import sys import sys
import importlib.machinery # importlib first so we can test #15386 via -m
import imp import imp
import importlib.machinery
from pkgutil import read_code, get_loader, get_importer from pkgutil import read_code, get_loader, get_importer
__all__ = [ __all__ = [

View file

@ -165,6 +165,9 @@ example, to run all the tests except for the gui tests, give the
option '-uall,-gui'. option '-uall,-gui'.
""" """
# We import importlib *ASAP* in order to test #15386
import importlib
import builtins import builtins
import faulthandler import faulthandler
import getopt import getopt

View file

@ -1,8 +1,9 @@
# We import importlib *ASAP* in order to test #15386
import importlib
import builtins import builtins
import imp import imp
from importlib.test.import_ import test_suite as importlib_import_test_suite from importlib.test.import_ import test_suite as importlib_import_test_suite
from importlib.test.import_ import util as importlib_util from importlib.test.import_ import util as importlib_util
import importlib
import marshal import marshal
import os import os
import platform import platform
@ -777,6 +778,15 @@ class ImportlibBootstrapTests(unittest.TestCase):
self.assertEqual(mod.__package__, 'importlib') self.assertEqual(mod.__package__, 'importlib')
self.assertTrue(mod.__file__.endswith('_bootstrap.py'), mod.__file__) self.assertTrue(mod.__file__.endswith('_bootstrap.py'), mod.__file__)
def test_there_can_be_only_one(self):
# Issue #15386 revealed a tricky loophole in the bootstrapping
# This test is technically redundant, since the bug caused importing
# this test module to crash completely, but it helps prove the point
from importlib import machinery
mod = sys.modules['_frozen_importlib']
self.assertIs(machinery.FileFinder, mod.FileFinder)
self.assertIs(imp.new_module, mod.new_module)
class ImportTracebackTests(unittest.TestCase): class ImportTracebackTests(unittest.TestCase):