2
2
import os
3
3
import sys
4
4
import py_compile
5
+ import uuid
5
6
6
7
7
8
def buildCode (c ):
@@ -28,19 +29,33 @@ def buildCode(c):
28
29
29
30
30
31
def getPythonCode (fname ):
31
- # Courtesy of Ned Batchelder, just get the code object from the .pyc file
32
+ # from https://stackoverflow.com/questions/32562163/how-can-i-understand-a-pyc-file-content
33
+ header_sizes = [
34
+ # (size, first version this applies to)
35
+ # pyc files were introduced in 0.9.2 way, way back in June 1991.
36
+ (8 , (0 , 9 , 2 )), # 2 bytes magic number, \r\n, 4 bytes UNIX timestamp
37
+ (12 , (3 , 6 )), # added 4 bytes file size
38
+ # bytes 4-8 are flags, meaning of 9-16 depends on what flags are set
39
+ # bit 0 not set: 9-12 timestamp, 13-16 file size
40
+ # bit 0 set: 9-16 file hash (SipHash-2-4, k0 = 4 bytes of the file, k1 = 0)
41
+ (16 , (3 , 7 )), # inserted 4 bytes bit flag field at 4-8
42
+ # future version may add more bytes still, at which point we can extend
43
+ # this table. It is correct for Python versions up to 3.9
44
+ ]
45
+ header_size = next (s for s , v in reversed (header_sizes ) if sys .version_info >= v )
46
+
32
47
with open (fname , "rb" ) as f :
33
- f .read (4 )
34
- f .read (4 )
35
- if sys .version_info >= (3 , 3 ):
36
- f .read (4 )
48
+ metadata = f .read (header_size ) # first header_size bytes are metadata
37
49
try :
38
- code = marshal .load (f )
39
- except (EOFError , TypeError , ValueError ):
40
- with open (fname , "rb" ) as fRetry :
41
- fRetry .read (16 )
42
- code = marshal .load (fRetry )
43
- return buildCode (code )
50
+ code = marshal .load (f ) # rest is a marshalled code object
51
+ except :
52
+ print ("WARNING: UNABLE TO MARSHAL CODE FROM PYC FILE!" )
53
+ return (uuid .uuid4 ())
54
+ if ("code" not in str (type (code ))):
55
+ print ("WARNING: INVALID CODE OBJECT READ FROM PYC FILE!" )
56
+ return (uuid .uuid4 ())
57
+ b = buildCode (code )
58
+ return b
44
59
45
60
46
61
def handler (tmpMutantName , mutant , sourceFile , uniqueMutants ):
0 commit comments