Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit befb14f

Browse files
committed
Merged revisions 69481 via svnmerge from
svn+ssh://[email protected]/python/trunk ........ r69481 | brett.cannon | 2009-02-09 18:07:38 -0800 (Mon, 09 Feb 2009) | 4 lines compileall used the ctime of bytecode and source to determine if the bytecode should be recreated. This created a timing hole. Fixed by just doing what import does; check the mtime and magic number. ........
1 parent 6691772 commit befb14f

4 files changed

Lines changed: 84 additions & 8 deletions

File tree

Lib/compileall.py

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,11 @@
1111
See module py_compile for details of the actual byte-compilation.
1212
1313
"""
14-
1514
import os
1615
import sys
1716
import py_compile
17+
import struct
18+
import imp
1819

1920
__all__ = ["compile_dir","compile_path"]
2021

@@ -54,11 +55,17 @@ def compile_dir(dir, maxlevels=10, ddir=None,
5455
if os.path.isfile(fullname):
5556
head, tail = name[:-3], name[-3:]
5657
if tail == '.py':
57-
cfile = fullname + (__debug__ and 'c' or 'o')
58-
ftime = os.stat(fullname).st_mtime
59-
try: ctime = os.stat(cfile).st_mtime
60-
except os.error: ctime = 0
61-
if (ctime > ftime) and not force: continue
58+
if not force:
59+
try:
60+
mtime = os.stat(fullname).st_mtime
61+
expect = struct.pack('<4sl', imp.get_magic(), mtime)
62+
cfile = fullname + (__debug__ and 'c' or 'o')
63+
with open(cfile, 'rb') as chandle:
64+
actual = chandle.read(8)
65+
if expect == actual:
66+
continue
67+
except IOError:
68+
pass
6269
if not quiet:
6370
print('Compiling', fullname, '...')
6471
try:
@@ -86,7 +93,8 @@ def compile_dir(dir, maxlevels=10, ddir=None,
8693
name != os.curdir and name != os.pardir and \
8794
os.path.isdir(fullname) and \
8895
not os.path.islink(fullname):
89-
if not compile_dir(fullname, maxlevels - 1, dfile, force, rx, quiet):
96+
if not compile_dir(fullname, maxlevels - 1, dfile, force, rx,
97+
quiet):
9098
success = 0
9199
return success
92100

Lib/test/test_compileall.py

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import compileall
2+
import imp
3+
import os
4+
import py_compile
5+
import shutil
6+
import struct
7+
import sys
8+
import tempfile
9+
import time
10+
from test import support
11+
import unittest
12+
13+
14+
class CompileallTests(unittest.TestCase):
15+
16+
def setUp(self):
17+
self.directory = tempfile.mkdtemp()
18+
self.source_path = os.path.join(self.directory, '_test.py')
19+
self.bc_path = self.source_path + ('c' if __debug__ else 'o')
20+
with open(self.source_path, 'w') as file:
21+
file.write('x = 123\n')
22+
23+
def tearDown(self):
24+
shutil.rmtree(self.directory)
25+
26+
def data(self):
27+
with open(self.bc_path, 'rb') as file:
28+
data = file.read(8)
29+
mtime = int(os.stat(self.source_path).st_mtime)
30+
compare = struct.pack('<4sl', imp.get_magic(), mtime)
31+
return data, compare
32+
33+
def recreation_check(self, metadata):
34+
"""Check that compileall recreates bytecode when the new metadata is
35+
used."""
36+
if not hasattr(os, 'stat'):
37+
return
38+
py_compile.compile(self.source_path)
39+
self.assertEqual(*self.data())
40+
with open(self.bc_path, 'rb') as file:
41+
bc = file.read()[len(metadata):]
42+
with open(self.bc_path, 'wb') as file:
43+
file.write(metadata)
44+
file.write(bc)
45+
self.assertNotEqual(*self.data())
46+
compileall.compile_dir(self.directory, force=False, quiet=True)
47+
self.assertTrue(*self.data())
48+
49+
def test_mtime(self):
50+
# Test a change in mtime leads to a new .pyc.
51+
self.recreation_check(struct.pack('<4sl', imp.get_magic(), 1))
52+
53+
def test_magic_number(self):
54+
# Test a change in mtime leads to a new .pyc.
55+
self.recreation_check(b'\0\0\0\0')
56+
57+
58+
def test_main():
59+
support.run_unittest(CompileallTests)
60+
61+
62+
if __name__ == "__main__":
63+
test_main()

Misc/ACKS

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ Virgil Dupras
183183
Andy Dustman
184184
Gary Duzan
185185
Eugene Dvurechenski
186-
Josip Dzolonga
186+
Josip Dzolonga
187187
Maxim Dzumanenko
188188
Walter D�rwald
189189
Hans Eckardt
@@ -234,6 +234,7 @@ Geoff Furnish
234234
Ulisses Furquim
235235
Hagen F�rstenau
236236
Achim Gaedke
237+
Martin von Gagern
237238
Lele Gaifax
238239
Santiago Gala
239240
Yitzchak Gale

Misc/NEWS

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,10 @@ Core and Builtins
163163
Library
164164
-------
165165

166+
- Issue #5128: Make compileall properly inspect bytecode to determine if needs
167+
to be recreated. This avoids a timing hole thanks to the old reliance on the
168+
ctime of the files involved.
169+
166170
- Issue #5122: Synchronize tk load failure check to prevent a potential
167171
deadlock.
168172

0 commit comments

Comments
 (0)