From 6931cc10c4a1e08161a58cf4b6b555b71cdc62b5 Mon Sep 17 00:00:00 2001 From: David Wilson Date: Thu, 8 Mar 2018 06:18:01 +0545 Subject: [PATCH] importer: avoid duplicate module load(!); closes #113. Amazed this one managed to scrape through for so long. Calling __import__ from within find_module() was causing the target module, in this case cookielib, to be loaded *then overwritten* by a subsequent duplicate load higher in the stack. The result is that cookielib was loaded twice, and, per usual Python import semantics, a reference to the partially initialized first cookielib was installed in sys.modules while its code executed. At the end of cookielib on 2.x, it imports _LWPCookieJar, which in turn imports the partially built cookielib from sys.modules, then subclasses the CookieJar from /that/ module. Everything is wonderful. Then the call returns back up into the import mechanism which restarts the entire process -- only this time, _LWPCookieJar is /not/ reinitialized, so the copy in sys.modules is still left with types pointing at the old module! So the duplicate import creates a new CookieJar which is not the base class of LWPCookieJar. Tada! 3 hours debugging. This is probably a performance fix in disguise, didn't realize things were so broken. It may also be a regression elsewhere. Urgently need to finish the tests. --- examples/playbook/hosts | 3 +-- examples/playbook/issue_113.yml | 10 ++++++---- mitogen/core.py | 14 ++++++++++++-- 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/examples/playbook/hosts b/examples/playbook/hosts index d507a38a..2fbb50c4 100644 --- a/examples/playbook/hosts +++ b/examples/playbook/hosts @@ -1,2 +1 @@ -#localhost -z +localhost diff --git a/examples/playbook/issue_113.yml b/examples/playbook/issue_113.yml index b28396a6..c6111243 100644 --- a/examples/playbook/issue_113.yml +++ b/examples/playbook/issue_113.yml @@ -1,7 +1,9 @@ - +--- - hosts: all + gather_facts: false tasks: + - name: Get auth token uri: url: "https://httpbin.org/post" @@ -13,7 +15,7 @@ register: r_token no_log: false run_once: true - delegate_to: localhost - - + register: foo + - assert: + that: foo.status == 200 diff --git a/mitogen/core.py b/mitogen/core.py index 57791423..ad0ef46d 100644 --- a/mitogen/core.py +++ b/mitogen/core.py @@ -452,6 +452,16 @@ class Importer(object): def __repr__(self): return 'Importer()' + def builtin_find_module(self, fullname): + parent, _, modname = fullname.rpartition('.') + if parent: + path = sys.modules[parent].__path__ + else: + path = None + fp, pathname, description = imp.find_module(modname, path) + if fp: + fp.close() + def find_module(self, fullname, path=None): if hasattr(_tls, 'running'): return None @@ -473,7 +483,7 @@ class Importer(object): return None try: - __import__(fullname, {}, {}, ['']) + self.builtin_find_module(fullname) _v and LOG.debug('%r: %r is available locally', self, fullname) except ImportError: _v and LOG.debug('find_module(%r) returning self', fullname) @@ -483,7 +493,7 @@ class Importer(object): def _refuse_imports(self, fullname): if is_blacklisted_import(self, fullname): - raise ImportError('Refused') + raise ImportError('Refused: ' + fullname) f = sys._getframe(2) requestee = f.f_globals['__name__']