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

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. 

16 

17Accross Python versions there are variations in: 

18 - Instructions 

19 - Instruction arguments 

20 - Shape of a code object 

21 - Construction of the lnotab 

22 

23Currently supported python versions are: 

24 - 3.6 

25 - 3.7 

26 - 3.8 

27 - 3.9 

28 - 3.10 

29""" 

30 

31import sys 

32import types 

33 

34PYTHON_VERSION = sys.version_info[:2] 

35 

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 ) 

42 

43### Instruction categories ### 

44 

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", 

52 

53 # 3.9 

54 "JUMP_IF_NOT_EXC_MATCH", 

55] 

56 

57UNCONDITIONAL_JUMPS = [ 

58 # common 

59 "JUMP_FORWARD", 

60 "JUMP_ABSOLUTE", 

61 

62 # 3.6 / 3.7 

63 "CONTINUE_LOOP", 

64 

65 # 3.8 

66 "CALL_FINALLY", 

67] 

68 

69ENDS_FUNCTION = [ 

70 # common 

71 "RAISE_VARARGS", 

72 "RETURN_VALUE", 

73 

74 # 3.9 

75 "RERAISE", 

76] 

77 

78HAVE_REL_REFERENCE = [ 

79 # common 

80 "SETUP_WITH", 

81 "JUMP_FORWARD", 

82 "FOR_ITER", 

83 "SETUP_FINALLY", 

84 "CALL_FINALLY", 

85 

86 # 3.6 / 3.7 

87 "SETUP_LOOP", 

88 "SETUP_EXCEPT", 

89] 

90 

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", 

98 

99 # 3.6 / 3.7 

100 "CONTINUE_LOOP", 

101 

102 # 3.9 

103 "JUMP_IF_NOT_EXC_MATCH", 

104] 

105 

106### Compare ops ### 

107 

108REVERSE_CMP_OP = [4, 5, 2, 3, 0, 1] 

109 

110### CodeTypes ### 

111 

112if (3, 6) <= PYTHON_VERSION <= (3, 7): 

113 

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) 

121 

122else: 

123 

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) 

131 

132 

133### Python 3.10 uses instruction (2 byte) offsets rather than byte offsets ### 

134 

135if PYTHON_VERSION >= (3, 10): 

136 

137 def jump_arg_bytes(arg: int) -> int: 

138 return arg * 2 

139 

140 def add_bytes_to_jump_arg(arg: int, size: int) -> int: 

141 return arg + size // 2 

142else: 

143 

144 def jump_arg_bytes(arg: int) -> int: 

145 return arg 

146 

147 def add_bytes_to_jump_arg(arg: int, size: int) -> int: 

148 return arg + size 

149 

150 

151### Lnotab handling ### 

152 

153if (3, 6) <= PYTHON_VERSION <= (3, 10): 

154 

155 def get_lnotab(code, listing): 

156 """Returns line number table.""" 

157 lnotab = [] 

158 current_lineno = listing[0].lineno 

159 i = 0 

160 

161 assert listing[0].lineno >= code.co_firstlineno 

162 

163 if listing[0].lineno > code.co_firstlineno: 

164 delta_lineno = listing[0].lineno - code.co_firstlineno 

165 

166 while delta_lineno > 127: 

167 lnotab.extend([0, 127]) 

168 delta_lineno -= 127 

169 

170 lnotab.extend([0, delta_lineno]) 

171 

172 while True: 

173 delta_bc = 0 

174 

175 while i < len(listing) and listing[i].lineno == current_lineno: 

176 delta_bc += listing[i].get_size() 

177 i += 1 

178 

179 if i >= len(listing): 

180 break 

181 

182 assert delta_bc > 0 

183 

184 delta_lineno = listing[i].lineno - current_lineno 

185 

186 while delta_bc > 255: 

187 lnotab.extend([255, 0]) 

188 delta_bc -= 255 

189 

190 if delta_lineno < 0: 

191 while delta_lineno < -128: 

192 lnotab.extend([delta_bc, 0x80]) 

193 delta_bc = 0 

194 delta_lineno += 128 

195 

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 

202 

203 lnotab.extend([delta_bc, delta_lineno]) 

204 current_lineno = listing[i].lineno 

205 

206 return bytes(lnotab)