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.
This commit is contained in:
parent
1b184d547f
commit
e52c919d67
|
@ -526,9 +526,9 @@ class _PyPycFileLoader(PyPycLoader, _PyFileLoader):
|
||||||
bytecode_path = self.bytecode_path(name)
|
bytecode_path = self.bytecode_path(name)
|
||||||
if not bytecode_path:
|
if not bytecode_path:
|
||||||
bytecode_path = self._base_path + _suffix_list(imp.PY_COMPILED)[0]
|
bytecode_path = self._base_path + _suffix_list(imp.PY_COMPILED)[0]
|
||||||
file = _io.FileIO(bytecode_path, 'w') # Assuming bytes.
|
|
||||||
try:
|
try:
|
||||||
with _closing(file) as bytecode_file:
|
# Assuming bytes.
|
||||||
|
with _closing(_io.FileIO(bytecode_path, 'w')) as bytecode_file:
|
||||||
bytecode_file.write(data)
|
bytecode_file.write(data)
|
||||||
return True
|
return True
|
||||||
except IOError as exc:
|
except IOError as exc:
|
||||||
|
|
|
@ -6,6 +6,7 @@ from . import util as source_util
|
||||||
import imp
|
import imp
|
||||||
import os
|
import os
|
||||||
import py_compile
|
import py_compile
|
||||||
|
import stat
|
||||||
import sys
|
import sys
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
|
@ -121,6 +122,10 @@ class BadBytecodeTest(unittest.TestCase):
|
||||||
But if the marshal data is bad, even if the magic number and timestamp
|
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].
|
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):
|
def import_(self, file, module_name):
|
||||||
|
@ -159,6 +164,7 @@ class BadBytecodeTest(unittest.TestCase):
|
||||||
self.assertEqual(bytecode_file.read(4), source_timestamp)
|
self.assertEqual(bytecode_file.read(4), source_timestamp)
|
||||||
|
|
||||||
# [bad marshal]
|
# [bad marshal]
|
||||||
|
@source_util.writes_bytecode_files
|
||||||
def test_bad_marshal(self):
|
def test_bad_marshal(self):
|
||||||
with source_util.create_modules('_temp') as mapping:
|
with source_util.create_modules('_temp') as mapping:
|
||||||
bytecode_path = source_util.bytecode_path(mapping['_temp'])
|
bytecode_path = source_util.bytecode_path(mapping['_temp'])
|
||||||
|
@ -172,6 +178,26 @@ class BadBytecodeTest(unittest.TestCase):
|
||||||
self.import_(mapping['_temp'], '_temp')
|
self.import_(mapping['_temp'], '_temp')
|
||||||
self.assertTrue('_temp' not in sys.modules)
|
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():
|
def test_main():
|
||||||
from test.support import run_unittest
|
from test.support import run_unittest
|
||||||
|
|
|
@ -472,6 +472,7 @@ Nick Maclaren
|
||||||
Don MacMillen
|
Don MacMillen
|
||||||
Steve Majewski
|
Steve Majewski
|
||||||
Grzegorz Makarewicz
|
Grzegorz Makarewicz
|
||||||
|
Dave Malcolm
|
||||||
Ken Manheimer
|
Ken Manheimer
|
||||||
Vladimir Marangozov
|
Vladimir Marangozov
|
||||||
David Marek
|
David Marek
|
||||||
|
|
|
@ -123,6 +123,9 @@ C-API
|
||||||
Library
|
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
|
- Issue #7264: Fix a possible deadlock when deallocating thread-local objects
|
||||||
which are part of a reference cycle.
|
which are part of a reference cycle.
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue