mirror of
				https://github.com/python/cpython.git
				synced 2025-11-04 03:44:55 +00:00 
			
		
		
		
	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
					
				
					 4 changed files with 32 additions and 2 deletions
				
			
		| 
						 | 
					@ -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…
	
	Add table
		Add a link
		
	
		Reference in a new issue