Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/atheris/version_dependent.py: 85%
62 statements
« prev ^ index » next coverage.py v7.0.1, created at 2022-12-25 06:11 +0000
« prev ^ index » next coverage.py v7.0.1, created at 2022-12-25 06:11 +0000
1# Copyright 2021 Google LLC
2# Copyright 2021 Fraunhofer FKIE
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15"""This module manages the version specific aspects of bytecode instrumentation.
17Accross Python versions there are variations in:
18 - Instructions
19 - Instruction arguments
20 - Shape of a code object
21 - Construction of the lnotab
23Currently supported python versions are:
24 - 3.6
25 - 3.7
26 - 3.8
27 - 3.9
28 - 3.10
29"""
31import sys
32import types
34PYTHON_VERSION = sys.version_info[:2]
36if PYTHON_VERSION < (3, 6) or PYTHON_VERSION > (3, 10):
37 raise RuntimeError(
38 "You are fuzzing on an unsupported python version: " +
39 f"{PYTHON_VERSION[0]}.{PYTHON_VERSION[1]}. Only 3.6 - 3.10 are " +
40 "supported by atheris 2.0. Use atheris 1.0 for older python versions."
41 )
43### Instruction categories ###
45CONDITIONAL_JUMPS = [
46 # common
47 "FOR_ITER",
48 "JUMP_IF_FALSE_OR_POP",
49 "JUMP_IF_TRUE_OR_POP",
50 "POP_JUMP_IF_FALSE",
51 "POP_JUMP_IF_TRUE",
53 # 3.9
54 "JUMP_IF_NOT_EXC_MATCH",
55]
57UNCONDITIONAL_JUMPS = [
58 # common
59 "JUMP_FORWARD",
60 "JUMP_ABSOLUTE",
62 # 3.6 / 3.7
63 "CONTINUE_LOOP",
65 # 3.8
66 "CALL_FINALLY",
67]
69ENDS_FUNCTION = [
70 # common
71 "RAISE_VARARGS",
72 "RETURN_VALUE",
74 # 3.9
75 "RERAISE",
76]
78HAVE_REL_REFERENCE = [
79 # common
80 "SETUP_WITH",
81 "JUMP_FORWARD",
82 "FOR_ITER",
83 "SETUP_FINALLY",
84 "CALL_FINALLY",
86 # 3.6 / 3.7
87 "SETUP_LOOP",
88 "SETUP_EXCEPT",
89]
91HAVE_ABS_REFERENCE = [
92 # common
93 "POP_JUMP_IF_TRUE",
94 "POP_JUMP_IF_FALSE",
95 "JUMP_IF_TRUE_OR_POP",
96 "JUMP_IF_FALSE_OR_POP",
97 "JUMP_ABSOLUTE",
99 # 3.6 / 3.7
100 "CONTINUE_LOOP",
102 # 3.9
103 "JUMP_IF_NOT_EXC_MATCH",
104]
106### Compare ops ###
108REVERSE_CMP_OP = [4, 5, 2, 3, 0, 1]
110### CodeTypes ###
112if (3, 6) <= PYTHON_VERSION <= (3, 7):
114 def get_code_object(code_obj, stacksize, bytecode, consts, names, lnotab):
115 return types.CodeType(code_obj.co_argcount, code_obj.co_kwonlyargcount,
116 code_obj.co_nlocals, stacksize, code_obj.co_flags,
117 bytecode, consts, names, code_obj.co_varnames,
118 code_obj.co_filename, code_obj.co_name,
119 code_obj.co_firstlineno, lnotab, code_obj.co_freevars,
120 code_obj.co_cellvars)
122else:
124 def get_code_object(code_obj, stacksize, bytecode, consts, names, lnotab):
125 return types.CodeType(code_obj.co_argcount, code_obj.co_posonlyargcount,
126 code_obj.co_kwonlyargcount, code_obj.co_nlocals,
127 stacksize, code_obj.co_flags, bytecode, consts, names,
128 code_obj.co_varnames, code_obj.co_filename,
129 code_obj.co_name, code_obj.co_firstlineno, lnotab,
130 code_obj.co_freevars, code_obj.co_cellvars)
133### Python 3.10 uses instruction (2 byte) offsets rather than byte offsets ###
135if PYTHON_VERSION >= (3, 10):
137 def jump_arg_bytes(arg: int) -> int:
138 return arg * 2
140 def add_bytes_to_jump_arg(arg: int, size: int) -> int:
141 return arg + size // 2
142else:
144 def jump_arg_bytes(arg: int) -> int:
145 return arg
147 def add_bytes_to_jump_arg(arg: int, size: int) -> int:
148 return arg + size
151### Lnotab handling ###
153if (3, 6) <= PYTHON_VERSION <= (3, 10):
155 def get_lnotab(code, listing):
156 """Returns line number table."""
157 lnotab = []
158 current_lineno = listing[0].lineno
159 i = 0
161 assert listing[0].lineno >= code.co_firstlineno
163 if listing[0].lineno > code.co_firstlineno:
164 delta_lineno = listing[0].lineno - code.co_firstlineno
166 while delta_lineno > 127:
167 lnotab.extend([0, 127])
168 delta_lineno -= 127
170 lnotab.extend([0, delta_lineno])
172 while True:
173 delta_bc = 0
175 while i < len(listing) and listing[i].lineno == current_lineno:
176 delta_bc += listing[i].get_size()
177 i += 1
179 if i >= len(listing):
180 break
182 assert delta_bc > 0
184 delta_lineno = listing[i].lineno - current_lineno
186 while delta_bc > 255:
187 lnotab.extend([255, 0])
188 delta_bc -= 255
190 if delta_lineno < 0:
191 while delta_lineno < -128:
192 lnotab.extend([delta_bc, 0x80])
193 delta_bc = 0
194 delta_lineno += 128
196 delta_lineno %= 256
197 else:
198 while delta_lineno > 127:
199 lnotab.extend([delta_bc, 127])
200 delta_bc = 0
201 delta_lineno -= 127
203 lnotab.extend([delta_bc, delta_lineno])
204 current_lineno = listing[i].lineno
206 return bytes(lnotab)