From 3d26b95ca7ad0f2a39f39606acf2935eb4344e67 Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Sat, 7 Nov 2009 23:57:20 +0000 Subject: [PATCH] Merged revisions 76146 via svnmerge from svn+ssh://pythondev@svn.python.org/python/branches/py3k ........ r76146 | brett.cannon | 2009-11-07 15:55:05 -0800 (Sat, 07 Nov 2009) | 6 lines When trying to write new bytecode, importlib was not catching the IOError thrown if the file happened to be read-only to keep the failure silent. Fixes issue #7187. Thanks, Dave Malcolm for the report and analysis of the problem. ........ --- Lib/importlib/_bootstrap.py | 4 +-- Lib/importlib/test/source/test_file_loader.py | 26 +++++++++++++++++++ Misc/ACKS | 1 + Misc/NEWS | 3 +++ 4 files changed, 32 insertions(+), 2 deletions(-) diff --git a/Lib/importlib/_bootstrap.py b/Lib/importlib/_bootstrap.py index 24bcff2f26e..03350b588a7 100644 --- a/Lib/importlib/_bootstrap.py +++ b/Lib/importlib/_bootstrap.py @@ -522,9 +522,9 @@ class _PyPycFileLoader(PyPycLoader, _PyFileLoader): bytecode_path = self.bytecode_path(name) if not bytecode_path: bytecode_path = self._base_path + _suffix_list(imp.PY_COMPILED)[0] - file = _io.FileIO(bytecode_path, 'w') # Assuming bytes. try: - with _closing(file) as bytecode_file: + # Assuming bytes. + with _closing(_io.FileIO(bytecode_path, 'w')) as bytecode_file: bytecode_file.write(data) return True except IOError as exc: diff --git a/Lib/importlib/test/source/test_file_loader.py b/Lib/importlib/test/source/test_file_loader.py index 0384e7d88c7..8b6efbfec60 100644 --- a/Lib/importlib/test/source/test_file_loader.py +++ b/Lib/importlib/test/source/test_file_loader.py @@ -6,6 +6,7 @@ from . import util as source_util import imp import os import py_compile +import stat import sys import unittest @@ -119,6 +120,10 @@ class BadBytecodeTest(unittest.TestCase): But if the marshal data is bad, even if the magic number and timestamp work, a ValueError is raised and the source is not used [bad marshal]. + The case of not being able to write out the bytecode must also be handled + as it's possible it was made read-only. In that instance the attempt to + write the bytecode should fail silently [bytecode read-only]. + """ def import_(self, file, module_name): @@ -157,6 +162,7 @@ class BadBytecodeTest(unittest.TestCase): self.assertEqual(bytecode_file.read(4), source_timestamp) # [bad marshal] + @source_util.writes_bytecode_files def test_bad_marshal(self): with source_util.create_modules('_temp') as mapping: bytecode_path = source_util.bytecode_path(mapping['_temp']) @@ -170,6 +176,26 @@ class BadBytecodeTest(unittest.TestCase): '_temp') self.assertTrue('_temp' not in sys.modules) + # [bytecode read-only] + @source_util.writes_bytecode_files + def test_read_only_bytecode(self): + with source_util.create_modules('_temp') as mapping: + # Create bytecode that will need to be re-created. + py_compile.compile(mapping['_temp']) + bytecode_path = source_util.bytecode_path(mapping['_temp']) + with open(bytecode_path, 'r+b') as bytecode_file: + bytecode_file.seek(0) + bytecode_file.write(b'\x00\x00\x00\x00') + # Make the bytecode read-only. + os.chmod(bytecode_path, + stat.S_IRUSR | stat.S_IRGRP | stat.S_IROTH) + try: + # Should not raise IOError! + self.import_(mapping['_temp'], '_temp') + finally: + # Make writable for eventual clean-up. + os.chmod(bytecode_path, stat.S_IWUSR) + def test_main(): from test.support import run_unittest diff --git a/Misc/ACKS b/Misc/ACKS index 7715730157f..f32b46b6fe0 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -466,6 +466,7 @@ Nick Maclaren Don MacMillen Steve Majewski Grzegorz Makarewicz +Dave Malcolm Ken Manheimer Vladimir Marangozov David Marek diff --git a/Misc/NEWS b/Misc/NEWS index 2ce607096a2..51dae2a66d8 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -40,6 +40,9 @@ Core and Builtins Library ------- +- Issue #7187: Importlib would not silence the IOError raised when trying to + write new bytecode when it was made read-only. + - Issue #7264: Fix a possible deadlock when deallocating thread-local objects which are part of a reference cycle.