Skip to content

Commit

Permalink
pythongh-120932: Check the pyc file mtime at import
Browse files Browse the repository at this point in the history
  • Loading branch information
serhiy-storchaka committed Jul 11, 2024
1 parent a852957 commit 37c8817
Showing 1 changed file with 21 additions and 5 deletions.
26 changes: 21 additions & 5 deletions Lib/importlib/_bootstrap_external.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import _imp
import _io
import sys
import time
import _warnings
import marshal

Expand Down Expand Up @@ -725,8 +726,8 @@ def _classify_pyc(data, name, exc_details):
return flags


def _validate_timestamp_pyc(data, source_mtime, source_size, name,
exc_details):
def _validate_timestamp_pyc(self, data, source_mtime, source_size, name,
bytecode_path, exc_details):
"""Validate a pyc against the source last-modified time.
*data* is the contents of the pyc file. (Only the first 16 bytes are
Expand All @@ -738,19 +739,32 @@ def _validate_timestamp_pyc(data, source_mtime, source_size, name,
*name* is the name of the module being imported. It is used for logging.
*bytecode_path* is the path of the pyc file.
*exc_details* is a dictionary passed to ImportError if it raised for
improved debugging.
An ImportError is raised if the bytecode is stale.
"""
if _unpack_uint32(data[8:12]) != (source_mtime & 0xFFFFFFFF):
timestamp = _unpack_uint32(data[8:12])
if timestamp != (int(source_mtime) & 0xFFFFFFFF):
message = f'bytecode is stale for {name!r}'
_bootstrap._verbose_message('{}', message)
raise ImportError(message, **exc_details)
if (source_size is not None and
_unpack_uint32(data[12:16]) != (source_size & 0xFFFFFFFF)):
raise ImportError(f'bytecode is stale for {name!r}', **exc_details)
if time.time() - source_mtime < 2:
try:
bytecode_mtime = self.path_mtime(bytecode_path)
except OSError:
pass
else:
if bytecode_mtime < source_mtime:
message = f'bytecode may be stale for {name!r}'
_bootstrap._verbose_message('{}', message)
raise ImportError(message, **exc_details)


def _validate_hash_pyc(data, source_hash, name, exc_details):
Expand Down Expand Up @@ -794,7 +808,7 @@ def _code_to_timestamp_pyc(code, mtime=0, source_size=0):
"Produce the data for a timestamp-based pyc."
data = bytearray(MAGIC_NUMBER)
data.extend(_pack_uint32(0))
data.extend(_pack_uint32(mtime))
data.extend(_pack_uint32(int(mtime)))
data.extend(_pack_uint32(source_size))
data.extend(marshal.dumps(code))
return data
Expand Down Expand Up @@ -1111,7 +1125,7 @@ def get_code(self, fullname):
except OSError:
pass
else:
source_mtime = int(st['mtime'])
source_mtime = st['mtime']
try:
data = self.get_data(bytecode_path)
except OSError:
Expand Down Expand Up @@ -1139,10 +1153,12 @@ def get_code(self, fullname):
exc_details)
else:
_validate_timestamp_pyc(
self,
data,
source_mtime,
st['size'],
fullname,
bytecode_path,
exc_details,
)
except (ImportError, EOFError):
Expand Down

0 comments on commit 37c8817

Please sign in to comment.