angr 9.2.102__py3-none-win_amd64.whl → 9.2.103__py3-none-win_amd64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of angr might be problematic. Click here for more details.

Files changed (240) hide show
  1. angr/__init__.py +1 -1
  2. angr/analyses/analysis.py +7 -6
  3. angr/analyses/calling_convention.py +33 -35
  4. angr/analyses/cdg.py +2 -4
  5. angr/analyses/cfg/cfb.py +4 -3
  6. angr/analyses/cfg/cfg_base.py +14 -14
  7. angr/analyses/cfg/cfg_emulated.py +3 -4
  8. angr/analyses/cfg/cfg_fast.py +46 -46
  9. angr/analyses/cfg/cfg_fast_soot.py +1 -2
  10. angr/analyses/cfg/cfg_job_base.py +2 -2
  11. angr/analyses/cfg/indirect_jump_resolvers/jumptable.py +14 -13
  12. angr/analyses/cfg/indirect_jump_resolvers/mips_elf_fast.py +5 -5
  13. angr/analyses/cfg_slice_to_sink/cfg_slice_to_sink.py +3 -3
  14. angr/analyses/complete_calling_conventions.py +13 -12
  15. angr/analyses/data_dep/data_dependency_analysis.py +24 -24
  16. angr/analyses/data_dep/dep_nodes.py +3 -3
  17. angr/analyses/ddg.py +1 -2
  18. angr/analyses/decompiler/ail_simplifier.py +35 -34
  19. angr/analyses/decompiler/block_io_finder.py +20 -20
  20. angr/analyses/decompiler/block_similarity.py +4 -6
  21. angr/analyses/decompiler/block_simplifier.py +17 -16
  22. angr/analyses/decompiler/callsite_maker.py +25 -10
  23. angr/analyses/decompiler/ccall_rewriters/amd64_ccalls.py +1 -3
  24. angr/analyses/decompiler/ccall_rewriters/rewriter_base.py +2 -4
  25. angr/analyses/decompiler/clinic.py +250 -45
  26. angr/analyses/decompiler/condition_processor.py +15 -8
  27. angr/analyses/decompiler/decompilation_cache.py +7 -7
  28. angr/analyses/decompiler/decompilation_options.py +4 -4
  29. angr/analyses/decompiler/decompiler.py +19 -15
  30. angr/analyses/decompiler/expression_counters.py +10 -9
  31. angr/analyses/decompiler/goto_manager.py +2 -4
  32. angr/analyses/decompiler/graph_region.py +9 -9
  33. angr/analyses/decompiler/jump_target_collector.py +1 -2
  34. angr/analyses/decompiler/optimization_passes/__init__.py +4 -3
  35. angr/analyses/decompiler/optimization_passes/code_motion.py +5 -6
  36. angr/analyses/decompiler/optimization_passes/const_derefs.py +4 -4
  37. angr/analyses/decompiler/optimization_passes/deadblock_remover.py +73 -0
  38. angr/analyses/decompiler/optimization_passes/engine_base.py +25 -3
  39. angr/analyses/decompiler/optimization_passes/expr_op_swapper.py +6 -5
  40. angr/analyses/decompiler/optimization_passes/flip_boolean_cmp.py +2 -2
  41. angr/analyses/decompiler/optimization_passes/inlined_string_transformation_simplifier.py +3 -0
  42. angr/analyses/decompiler/optimization_passes/ite_expr_converter.py +2 -2
  43. angr/analyses/decompiler/optimization_passes/lowered_switch_simplifier.py +17 -17
  44. angr/analyses/decompiler/optimization_passes/optimization_pass.py +12 -13
  45. angr/analyses/decompiler/optimization_passes/register_save_area_simplifier.py +25 -21
  46. angr/analyses/decompiler/optimization_passes/ret_addr_save_simplifier.py +3 -3
  47. angr/analyses/decompiler/optimization_passes/ret_deduplicator.py +1 -2
  48. angr/analyses/decompiler/optimization_passes/return_duplicator_base.py +7 -7
  49. angr/analyses/decompiler/optimization_passes/spilled_register_finder.py +18 -0
  50. angr/analyses/decompiler/optimization_passes/stack_canary_simplifier.py +2 -3
  51. angr/analyses/decompiler/optimization_passes/win_stack_canary_simplifier.py +1 -2
  52. angr/analyses/decompiler/optimization_passes/x86_gcc_getpc_simplifier.py +2 -2
  53. angr/analyses/decompiler/peephole_optimizations/__init__.py +4 -3
  54. angr/analyses/decompiler/peephole_optimizations/base.py +13 -15
  55. angr/analyses/decompiler/peephole_optimizations/bswap.py +1 -3
  56. angr/analyses/decompiler/peephole_optimizations/cmpord_rewriter.py +72 -0
  57. angr/analyses/decompiler/peephole_optimizations/const_mull_a_shift.py +1 -2
  58. angr/analyses/decompiler/peephole_optimizations/eager_eval.py +1 -1
  59. angr/analyses/decompiler/peephole_optimizations/inlined_strcpy.py +5 -10
  60. angr/analyses/decompiler/peephole_optimizations/inlined_strcpy_consolidation.py +3 -4
  61. angr/analyses/decompiler/peephole_optimizations/inlined_wstrcpy.py +7 -10
  62. angr/analyses/decompiler/peephole_optimizations/rewrite_bit_extractions.py +2 -3
  63. angr/analyses/decompiler/peephole_optimizations/sar_to_signed_div.py +1 -2
  64. angr/analyses/decompiler/peephole_optimizations/tidy_stack_addr.py +4 -4
  65. angr/analyses/decompiler/redundant_label_remover.py +4 -5
  66. angr/analyses/decompiler/region_identifier.py +4 -5
  67. angr/analyses/decompiler/region_simplifiers/cascading_cond_transformer.py +1 -2
  68. angr/analyses/decompiler/region_simplifiers/expr_folding.py +19 -20
  69. angr/analyses/decompiler/region_simplifiers/goto.py +2 -3
  70. angr/analyses/decompiler/region_simplifiers/loop.py +1 -2
  71. angr/analyses/decompiler/region_simplifiers/node_address_finder.py +1 -2
  72. angr/analyses/decompiler/region_simplifiers/region_simplifier.py +1 -3
  73. angr/analyses/decompiler/region_simplifiers/switch_cluster_simplifier.py +19 -19
  74. angr/analyses/decompiler/return_maker.py +1 -2
  75. angr/analyses/decompiler/structured_codegen/base.py +5 -6
  76. angr/analyses/decompiler/structured_codegen/c.py +39 -38
  77. angr/analyses/decompiler/structuring/__init__.py +1 -1
  78. angr/analyses/decompiler/structuring/dream.py +17 -16
  79. angr/analyses/decompiler/structuring/phoenix.py +45 -46
  80. angr/analyses/decompiler/structuring/recursive_structurer.py +4 -4
  81. angr/analyses/decompiler/structuring/structurer_base.py +16 -15
  82. angr/analyses/decompiler/structuring/structurer_nodes.py +10 -9
  83. angr/analyses/decompiler/utils.py +17 -16
  84. angr/analyses/disassembly.py +7 -6
  85. angr/analyses/flirt.py +9 -9
  86. angr/analyses/forward_analysis/forward_analysis.py +15 -14
  87. angr/analyses/forward_analysis/visitors/function_graph.py +1 -2
  88. angr/analyses/forward_analysis/visitors/graph.py +16 -15
  89. angr/analyses/propagator/engine_ail.py +30 -26
  90. angr/analyses/propagator/outdated_definition_walker.py +8 -7
  91. angr/analyses/propagator/propagator.py +11 -13
  92. angr/analyses/proximity_graph.py +21 -21
  93. angr/analyses/reaching_definitions/__init__.py +3 -3
  94. angr/analyses/reaching_definitions/call_trace.py +3 -6
  95. angr/analyses/reaching_definitions/dep_graph.py +41 -48
  96. angr/analyses/reaching_definitions/engine_ail.py +11 -5
  97. angr/analyses/reaching_definitions/engine_vex.py +9 -8
  98. angr/analyses/reaching_definitions/function_handler.py +51 -34
  99. angr/analyses/reaching_definitions/heap_allocator.py +3 -4
  100. angr/analyses/reaching_definitions/rd_initializer.py +8 -8
  101. angr/analyses/reaching_definitions/rd_state.py +57 -58
  102. angr/analyses/reaching_definitions/reaching_definitions.py +18 -17
  103. angr/analyses/reaching_definitions/subject.py +2 -3
  104. angr/analyses/stack_pointer_tracker.py +15 -6
  105. angr/analyses/typehoon/dfa.py +4 -4
  106. angr/analyses/typehoon/simple_solver.py +48 -52
  107. angr/analyses/typehoon/translator.py +3 -6
  108. angr/analyses/typehoon/typeconsts.py +13 -14
  109. angr/analyses/typehoon/typehoon.py +9 -9
  110. angr/analyses/typehoon/typevars.py +18 -17
  111. angr/analyses/variable_recovery/engine_ail.py +5 -5
  112. angr/analyses/variable_recovery/engine_base.py +25 -21
  113. angr/analyses/variable_recovery/irsb_scanner.py +8 -9
  114. angr/analyses/variable_recovery/variable_recovery.py +1 -2
  115. angr/analyses/variable_recovery/variable_recovery_base.py +14 -13
  116. angr/analyses/variable_recovery/variable_recovery_fast.py +8 -8
  117. angr/analyses/veritesting.py +1 -2
  118. angr/analyses/vfg.py +57 -56
  119. angr/analyses/xrefs.py +1 -2
  120. angr/angrdb/db.py +7 -7
  121. angr/angrdb/serializers/kb.py +16 -13
  122. angr/angrdb/serializers/loader.py +1 -2
  123. angr/angrdb/serializers/structured_code.py +2 -2
  124. angr/annocfg.py +1 -2
  125. angr/block.py +16 -6
  126. angr/calling_conventions.py +27 -27
  127. angr/code_location.py +8 -8
  128. angr/codenode.py +1 -2
  129. angr/concretization_strategies/max.py +1 -3
  130. angr/distributed/server.py +1 -3
  131. angr/distributed/worker.py +1 -2
  132. angr/engines/engine.py +2 -3
  133. angr/engines/light/engine.py +4 -4
  134. angr/engines/pcode/behavior.py +20 -2
  135. angr/engines/pcode/emulate.py +1 -1
  136. angr/engines/pcode/engine.py +7 -7
  137. angr/engines/pcode/lifter.py +78 -77
  138. angr/engines/vex/claripy/ccall.py +1 -2
  139. angr/engines/vex/claripy/datalayer.py +1 -2
  140. angr/engines/vex/light/light.py +1 -2
  141. angr/exploration_techniques/tracer.py +4 -4
  142. angr/factory.py +12 -15
  143. angr/flirt/__init__.py +8 -8
  144. angr/flirt/build_sig.py +2 -3
  145. angr/keyed_region.py +2 -2
  146. angr/knowledge_base/knowledge_base.py +3 -3
  147. angr/knowledge_plugins/callsite_prototypes.py +4 -6
  148. angr/knowledge_plugins/cfg/cfg_manager.py +19 -6
  149. angr/knowledge_plugins/cfg/cfg_model.py +26 -27
  150. angr/knowledge_plugins/cfg/cfg_node.py +2 -2
  151. angr/knowledge_plugins/cfg/indirect_jump.py +6 -8
  152. angr/knowledge_plugins/cfg/memory_data.py +8 -9
  153. angr/knowledge_plugins/custom_strings.py +1 -3
  154. angr/knowledge_plugins/debug_variables.py +2 -2
  155. angr/knowledge_plugins/functions/function.py +21 -22
  156. angr/knowledge_plugins/functions/function_manager.py +5 -5
  157. angr/knowledge_plugins/indirect_jumps.py +1 -3
  158. angr/knowledge_plugins/key_definitions/atoms.py +7 -7
  159. angr/knowledge_plugins/key_definitions/definition.py +14 -14
  160. angr/knowledge_plugins/key_definitions/environment.py +5 -7
  161. angr/knowledge_plugins/key_definitions/heap_address.py +1 -3
  162. angr/knowledge_plugins/key_definitions/key_definition_manager.py +3 -2
  163. angr/knowledge_plugins/key_definitions/live_definitions.py +60 -59
  164. angr/knowledge_plugins/key_definitions/liveness.py +16 -16
  165. angr/knowledge_plugins/key_definitions/rd_model.py +15 -15
  166. angr/knowledge_plugins/key_definitions/uses.py +11 -11
  167. angr/knowledge_plugins/patches.py +4 -8
  168. angr/knowledge_plugins/propagations/prop_value.py +10 -9
  169. angr/knowledge_plugins/propagations/propagation_manager.py +3 -5
  170. angr/knowledge_plugins/propagations/propagation_model.py +9 -9
  171. angr/knowledge_plugins/propagations/states.py +52 -22
  172. angr/knowledge_plugins/structured_code/manager.py +2 -2
  173. angr/knowledge_plugins/sync/sync_controller.py +3 -3
  174. angr/knowledge_plugins/variables/variable_access.py +4 -4
  175. angr/knowledge_plugins/variables/variable_manager.py +39 -39
  176. angr/knowledge_plugins/xrefs/xref.py +9 -11
  177. angr/knowledge_plugins/xrefs/xref_manager.py +3 -4
  178. angr/lib/angr_native.dll +0 -0
  179. angr/misc/ansi.py +1 -2
  180. angr/misc/autoimport.py +3 -3
  181. angr/misc/plugins.py +9 -9
  182. angr/procedures/definitions/__init__.py +16 -16
  183. angr/procedures/definitions/linux_kernel.py +1 -1
  184. angr/procedures/definitions/parse_win32json.py +1 -1
  185. angr/procedures/java_jni/__init__.py +1 -1
  186. angr/procedures/java_jni/array_operations.py +1 -2
  187. angr/procedures/java_jni/method_calls.py +1 -2
  188. angr/procedures/posix/inet_ntoa.py +1 -2
  189. angr/procedures/stubs/format_parser.py +3 -3
  190. angr/project.py +13 -11
  191. angr/sim_manager.py +12 -12
  192. angr/sim_procedure.py +7 -3
  193. angr/sim_state.py +2 -2
  194. angr/sim_type.py +60 -45
  195. angr/sim_variable.py +5 -5
  196. angr/simos/simos.py +1 -2
  197. angr/simos/userland.py +1 -2
  198. angr/state_plugins/callstack.py +3 -2
  199. angr/state_plugins/history.py +1 -2
  200. angr/state_plugins/solver.py +34 -34
  201. angr/storage/memory_mixins/__init__.py +4 -3
  202. angr/storage/memory_mixins/actions_mixin.py +1 -3
  203. angr/storage/memory_mixins/address_concretization_mixin.py +1 -3
  204. angr/storage/memory_mixins/convenient_mappings_mixin.py +3 -4
  205. angr/storage/memory_mixins/default_filler_mixin.py +1 -1
  206. angr/storage/memory_mixins/label_merger_mixin.py +2 -2
  207. angr/storage/memory_mixins/multi_value_merger_mixin.py +4 -3
  208. angr/storage/memory_mixins/paged_memory/page_backer_mixins.py +9 -8
  209. angr/storage/memory_mixins/paged_memory/paged_memory_mixin.py +12 -11
  210. angr/storage/memory_mixins/paged_memory/pages/cooperation.py +8 -8
  211. angr/storage/memory_mixins/paged_memory/pages/history_tracking_mixin.py +2 -3
  212. angr/storage/memory_mixins/paged_memory/pages/list_page.py +10 -11
  213. angr/storage/memory_mixins/paged_memory/pages/multi_values.py +11 -10
  214. angr/storage/memory_mixins/paged_memory/pages/mv_list_page.py +18 -17
  215. angr/storage/memory_mixins/paged_memory/pages/ultra_page.py +12 -11
  216. angr/storage/memory_mixins/regioned_memory/abstract_address_descriptor.py +3 -3
  217. angr/storage/memory_mixins/regioned_memory/abstract_merger_mixin.py +3 -2
  218. angr/storage/memory_mixins/regioned_memory/region_data.py +1 -2
  219. angr/storage/memory_mixins/regioned_memory/region_meta_mixin.py +2 -2
  220. angr/storage/memory_mixins/regioned_memory/regioned_address_concretization_mixin.py +3 -3
  221. angr/storage/memory_mixins/regioned_memory/regioned_memory_mixin.py +18 -21
  222. angr/storage/memory_mixins/size_resolution_mixin.py +1 -2
  223. angr/storage/memory_mixins/symbolic_merger_mixin.py +3 -2
  224. angr/storage/memory_mixins/top_merger_mixin.py +3 -2
  225. angr/storage/memory_object.py +2 -4
  226. angr/utils/algo.py +3 -2
  227. angr/utils/dynamic_dictlist.py +5 -5
  228. angr/utils/formatting.py +4 -4
  229. angr/utils/funcid.py +1 -2
  230. angr/utils/graph.py +5 -6
  231. angr/utils/library.py +5 -5
  232. angr/utils/mp.py +5 -4
  233. angr/utils/segment_list.py +3 -4
  234. angr/utils/typing.py +3 -2
  235. {angr-9.2.102.dist-info → angr-9.2.103.dist-info}/METADATA +9 -11
  236. {angr-9.2.102.dist-info → angr-9.2.103.dist-info}/RECORD +240 -237
  237. {angr-9.2.102.dist-info → angr-9.2.103.dist-info}/LICENSE +0 -0
  238. {angr-9.2.102.dist-info → angr-9.2.103.dist-info}/WHEEL +0 -0
  239. {angr-9.2.102.dist-info → angr-9.2.103.dist-info}/entry_points.txt +0 -0
  240. {angr-9.2.102.dist-info → angr-9.2.103.dist-info}/top_level.txt +0 -0
@@ -216,7 +216,7 @@ class EagerEvaluation(PeepholeOptimizationExprBase):
216
216
 
217
217
  @staticmethod
218
218
  def _optimize_convert(expr: Convert):
219
- if isinstance(expr.operand, Const):
219
+ if isinstance(expr.operand, Const) and expr.from_type == Convert.TYPE_INT and expr.to_type == Convert.TYPE_INT:
220
220
  if expr.from_bits > expr.to_bits:
221
221
  # truncation
222
222
  mask = (1 << expr.to_bits) - 1
@@ -1,5 +1,4 @@
1
1
  # pylint:disable=arguments-differ
2
- from typing import Tuple, Optional, Dict, List
3
2
  import string
4
3
 
5
4
  from archinfo import Endness
@@ -25,7 +24,7 @@ class InlinedStrcpy(PeepholeOptimizationStmtBase):
25
24
  stmt_classes = (Store,)
26
25
 
27
26
  def optimize(self, stmt: Store, stmt_idx: int = None, block=None, **kwargs):
28
- if isinstance(stmt.data, Const):
27
+ if isinstance(stmt.data, Const) and isinstance(stmt.data.value, int):
29
28
  r, s = self.is_integer_likely_a_string(stmt.data.value, stmt.data.size, stmt.endness)
30
29
  if r:
31
30
  # replace it with a call to strncpy
@@ -43,9 +42,7 @@ class InlinedStrcpy(PeepholeOptimizationStmtBase):
43
42
 
44
43
  # scan forward in the current block to find all consecutive constant stores
45
44
  if block is not None and stmt_idx is not None:
46
- all_constant_stores: Dict[int, Tuple[int, Optional[Const]]] = self.collect_constant_stores(
47
- block, stmt_idx
48
- )
45
+ all_constant_stores: dict[int, tuple[int, Const | None]] = self.collect_constant_stores(block, stmt_idx)
49
46
  if all_constant_stores:
50
47
  offsets = sorted(all_constant_stores.keys())
51
48
  next_offset = min(offsets)
@@ -87,7 +84,7 @@ class InlinedStrcpy(PeepholeOptimizationStmtBase):
87
84
  return None
88
85
 
89
86
  @staticmethod
90
- def stride_to_int(stride: List[Tuple[int, int, Const]]) -> Tuple[int, int]:
87
+ def stride_to_int(stride: list[tuple[int, int, Const]]) -> tuple[int, int]:
91
88
  stride = sorted(stride, key=lambda x: x[0])
92
89
  n = 0
93
90
  size = 0
@@ -98,7 +95,7 @@ class InlinedStrcpy(PeepholeOptimizationStmtBase):
98
95
  return n, size
99
96
 
100
97
  @staticmethod
101
- def collect_constant_stores(block, starting_stmt_idx: int) -> Dict[int, Tuple[int, Optional[Const]]]:
98
+ def collect_constant_stores(block, starting_stmt_idx: int) -> dict[int, tuple[int, Const | None]]:
102
99
  r = {}
103
100
  for idx, stmt in enumerate(block.statements):
104
101
  if idx < starting_stmt_idx:
@@ -112,9 +109,7 @@ class InlinedStrcpy(PeepholeOptimizationStmtBase):
112
109
  return r
113
110
 
114
111
  @staticmethod
115
- def is_integer_likely_a_string(
116
- v: int, size: int, endness: Endness, min_length: int = 4
117
- ) -> Tuple[bool, Optional[str]]:
112
+ def is_integer_likely_a_string(v: int, size: int, endness: Endness, min_length: int = 4) -> tuple[bool, str | None]:
118
113
  # we need at least four bytes of printable characters
119
114
 
120
115
  chars = []
@@ -1,5 +1,4 @@
1
1
  # pylint:disable=arguments-differ
2
- from typing import List, Tuple, Optional
3
2
 
4
3
  from ailment.expression import Expression, BinaryOp, Const, Register, StackBaseOffset
5
4
  from ailment.statement import Call, Store
@@ -18,7 +17,7 @@ class InlinedStrcpyConsolidation(PeepholeOptimizationMultiStmtBase):
18
17
  NAME = "Consolidate multiple inlined strcpy calls"
19
18
  stmt_classes = ((Call, Call), (Call, Store))
20
19
 
21
- def optimize(self, stmts: List[Call], **kwargs):
20
+ def optimize(self, stmts: list[Call], **kwargs):
22
21
  last_stmt, stmt = stmts
23
22
  if InlinedStrcpyConsolidation._is_inlined_strcpy(last_stmt):
24
23
  s_last: bytes = self.kb.custom_strings[last_stmt.args[1].value]
@@ -79,7 +78,7 @@ class InlinedStrcpyConsolidation(PeepholeOptimizationMultiStmtBase):
79
78
  return False
80
79
 
81
80
  @staticmethod
82
- def _parse_addr(addr: Expression) -> Tuple[Expression, int]:
81
+ def _parse_addr(addr: Expression) -> tuple[Expression, int]:
83
82
  if isinstance(addr, Register):
84
83
  return addr, 0
85
84
  if isinstance(addr, StackBaseOffset):
@@ -95,7 +94,7 @@ class InlinedStrcpyConsolidation(PeepholeOptimizationMultiStmtBase):
95
94
  return addr, 0
96
95
 
97
96
  @staticmethod
98
- def _get_delta(addr_0: Expression, addr_1: Expression) -> Optional[int]:
97
+ def _get_delta(addr_0: Expression, addr_1: Expression) -> int | None:
99
98
  base_0, offset_0 = InlinedStrcpyConsolidation._parse_addr(addr_0)
100
99
  base_1, offset_1 = InlinedStrcpyConsolidation._parse_addr(addr_1)
101
100
  if base_0.likes(base_1):
@@ -1,5 +1,4 @@
1
1
  # pylint:disable=arguments-differ
2
- from typing import Tuple, Optional, Dict, List
3
2
  import string
4
3
 
5
4
  from archinfo import Endness
@@ -25,7 +24,7 @@ class InlinedWstrcpy(PeepholeOptimizationStmtBase):
25
24
  stmt_classes = (Store,)
26
25
 
27
26
  def optimize(self, stmt: Store, stmt_idx: int = None, block=None, **kwargs):
28
- if isinstance(stmt.data, Const):
27
+ if isinstance(stmt.data, Const) and isinstance(stmt.data.value, int):
29
28
  r, s = self.is_integer_likely_a_wide_string(stmt.data.value, stmt.data.size, stmt.endness)
30
29
  if r:
31
30
  # replace it with a call to strncpy
@@ -43,9 +42,7 @@ class InlinedWstrcpy(PeepholeOptimizationStmtBase):
43
42
 
44
43
  # scan forward in the current block to find all consecutive constant stores
45
44
  if block is not None and stmt_idx is not None:
46
- all_constant_stores: Dict[int, Tuple[int, Optional[Const]]] = self.collect_constant_stores(
47
- block, stmt_idx
48
- )
45
+ all_constant_stores: dict[int, tuple[int, Const | None]] = self.collect_constant_stores(block, stmt_idx)
49
46
  if all_constant_stores:
50
47
  offsets = sorted(all_constant_stores.keys())
51
48
  next_offset = min(offsets)
@@ -87,7 +84,7 @@ class InlinedWstrcpy(PeepholeOptimizationStmtBase):
87
84
  return None
88
85
 
89
86
  @staticmethod
90
- def stride_to_int(stride: List[Tuple[int, int, Const]]) -> Tuple[int, int]:
87
+ def stride_to_int(stride: list[tuple[int, int, Const]]) -> tuple[int, int]:
91
88
  stride = sorted(stride, key=lambda x: x[0])
92
89
  n = 0
93
90
  size = 0
@@ -98,7 +95,7 @@ class InlinedWstrcpy(PeepholeOptimizationStmtBase):
98
95
  return n, size
99
96
 
100
97
  @staticmethod
101
- def collect_constant_stores(block, starting_stmt_idx: int) -> Dict[int, Tuple[int, Optional[Const]]]:
98
+ def collect_constant_stores(block, starting_stmt_idx: int) -> dict[int, tuple[int, Const | None]]:
102
99
  r = {}
103
100
  for idx, stmt in enumerate(block.statements):
104
101
  if idx < starting_stmt_idx:
@@ -112,17 +109,17 @@ class InlinedWstrcpy(PeepholeOptimizationStmtBase):
112
109
  return r
113
110
 
114
111
  @staticmethod
115
- def even_offsets_are_zero(lst: List[str]) -> bool:
112
+ def even_offsets_are_zero(lst: list[str]) -> bool:
116
113
  return all(ch == "\x00" for i, ch in enumerate(lst) if i % 2 == 0)
117
114
 
118
115
  @staticmethod
119
- def odd_offsets_are_zero(lst: List[str]) -> bool:
116
+ def odd_offsets_are_zero(lst: list[str]) -> bool:
120
117
  return all(ch == "\x00" for i, ch in enumerate(lst) if i % 2 == 1)
121
118
 
122
119
  @staticmethod
123
120
  def is_integer_likely_a_wide_string(
124
121
  v: int, size: int, endness: Endness, min_length: int = 4
125
- ) -> Tuple[bool, Optional[str]]:
122
+ ) -> tuple[bool, str | None]:
126
123
  # we need at least four bytes of printable characters
127
124
 
128
125
  chars = []
@@ -1,5 +1,4 @@
1
1
  # pylint:disable=too-many-boolean-expressions
2
- from typing import Optional, Dict, Tuple
3
2
  from ailment.expression import Expression, BinaryOp, Const, Convert, ITE
4
3
 
5
4
  from .base import PeepholeOptimizationExprBase
@@ -36,7 +35,7 @@ class RewriteBitExtractions(PeepholeOptimizationExprBase):
36
35
 
37
36
  return None
38
37
 
39
- def _extract_bitoffset_to_expr_mapping(self, expr: BinaryOp) -> Optional[Dict[int, Expression]]:
38
+ def _extract_bitoffset_to_expr_mapping(self, expr: BinaryOp) -> dict[int, Expression] | None:
40
39
  d = {}
41
40
  if isinstance(expr, BinaryOp) and expr.op == "Or":
42
41
  for arg in expr.operands:
@@ -61,7 +60,7 @@ class RewriteBitExtractions(PeepholeOptimizationExprBase):
61
60
  return d
62
61
 
63
62
  @staticmethod
64
- def _get_setbit(expr: Expression) -> Optional[Tuple[int, Expression]]:
63
+ def _get_setbit(expr: Expression) -> tuple[int, Expression] | None:
65
64
  """
66
65
  Test if expr is a single-bit expression, and if it is, return the bit offset that it sets and the inner
67
66
  expression that sets the bit.
@@ -1,4 +1,3 @@
1
- from typing import Optional, Tuple
2
1
  from ailment.expression import Convert, BinaryOp, Const, ITE, Expression, Register
3
2
 
4
3
  from .base import PeepholeOptimizationExprBase
@@ -75,7 +74,7 @@ class SarToSignedDiv(PeepholeOptimizationExprBase):
75
74
  return None
76
75
 
77
76
  @staticmethod
78
- def _check_signedness(expr) -> Optional[Tuple[bool, int, Expression]]:
77
+ def _check_signedness(expr) -> tuple[bool, int, Expression] | None:
79
78
  # return a tuple of ( is_signed (False for is_unsigned), bits of the expression to test for signedness, and the
80
79
  # expression itself ).
81
80
  if isinstance(expr, BinaryOp):
@@ -1,4 +1,4 @@
1
- from typing import List, Tuple, TYPE_CHECKING
1
+ from typing import TYPE_CHECKING
2
2
 
3
3
  from ailment.expression import UnaryOp, BinaryOp, StackBaseOffset, Const
4
4
 
@@ -30,8 +30,8 @@ class TidyStackAddr(PeepholeOptimizationExprBase):
30
30
  return None
31
31
 
32
32
  # consolidate all expressions into a list of expressions with their signs (True for +, False for -)
33
- all_operands: List[Tuple[bool, "Expression"]] = []
34
- stack: List[Tuple[bool, "Expression"]] = [(True, expr)]
33
+ all_operands: list[tuple[bool, "Expression"]] = []
34
+ stack: list[tuple[bool, "Expression"]] = [(True, expr)]
35
35
  stackbase_count = 0
36
36
  while stack:
37
37
  sign, item = stack.pop(0)
@@ -54,7 +54,7 @@ class TidyStackAddr(PeepholeOptimizationExprBase):
54
54
 
55
55
  # collect all constants until the next StackBaseOffset object and merge them into the prior StackBaseOffset
56
56
  # object.
57
- stackbaseoffset_objs: List[Tuple[bool, StackBaseOffset]] = []
57
+ stackbaseoffset_objs: list[tuple[bool, StackBaseOffset]] = []
58
58
 
59
59
  # find StackBaseOffset objects and record their indices
60
60
  stackbaseoffset_indices = []
@@ -1,5 +1,4 @@
1
1
  # pylint:disable=unused-argument
2
- from typing import Set, Optional, Tuple, Dict
3
2
 
4
3
  import ailment
5
4
 
@@ -18,12 +17,12 @@ class RedundantLabelRemover:
18
17
  anywhere (determined by jump_targets), or (b) are deemed replaceable by the first pass.
19
18
  """
20
19
 
21
- def __init__(self, node, jump_targets: Set[Tuple[int, Optional[int]]]):
20
+ def __init__(self, node, jump_targets: set[tuple[int, int | None]]):
22
21
  self.root = node
23
22
  self._jump_targets = jump_targets
24
23
 
25
- self._labels_to_remove: Set[ailment.Stmt.Label] = set()
26
- self._new_jump_target: Dict[Tuple[int, Optional[int]], Tuple[int, Optional[int]]] = {}
24
+ self._labels_to_remove: set[ailment.Stmt.Label] = set()
25
+ self._new_jump_target: dict[tuple[int, int | None], tuple[int, int | None]] = {}
27
26
 
28
27
  handlers0 = {
29
28
  SequenceNode: self._handle_Sequence,
@@ -44,7 +43,7 @@ class RedundantLabelRemover:
44
43
 
45
44
  def _handle_Sequence(self, node: SequenceNode, **kwargs):
46
45
  # merge consecutive labels
47
- last_label_addr: Optional[Tuple[int, Optional[int]]] = None
46
+ last_label_addr: tuple[int, int | None] | None = None
48
47
  for node_ in node.nodes:
49
48
  if isinstance(node_, ailment.Block):
50
49
  if node_.statements:
@@ -1,7 +1,6 @@
1
1
  from itertools import count
2
2
  from collections import defaultdict
3
3
  import logging
4
- from typing import List, Optional, Union
5
4
 
6
5
  import networkx
7
6
 
@@ -59,7 +58,7 @@ class RegionIdentifier(Analysis):
59
58
 
60
59
  self.region = None
61
60
  self._start_node = None
62
- self._loop_headers: Optional[List] = None
61
+ self._loop_headers: list | None = None
63
62
  self.regions_by_block_addrs = []
64
63
  self._largest_successor_tree_outside_loop = largest_successor_tree_outside_loop
65
64
  self._force_loop_single_exit = force_loop_single_exit
@@ -102,7 +101,7 @@ class RegionIdentifier(Analysis):
102
101
  # make regions into block address lists
103
102
  self.regions_by_block_addrs = self._make_regions_by_block_addrs()
104
103
 
105
- def _make_regions_by_block_addrs(self) -> List[List[int]]:
104
+ def _make_regions_by_block_addrs(self) -> list[list[int]]:
106
105
  """
107
106
  Creates a list of addr lists representing each region without recursion. A single region is defined
108
107
  as a set of only blocks, no Graphs containing nested regions. The list contains the address of each
@@ -190,7 +189,7 @@ class RegionIdentifier(Analysis):
190
189
  else:
191
190
  break
192
191
 
193
- def _find_loop_headers(self, graph: networkx.DiGraph) -> List:
192
+ def _find_loop_headers(self, graph: networkx.DiGraph) -> list:
194
193
  heads = {t for _, t in dfs_back_edges(graph, self._start_node)}
195
194
  return GraphUtils.quasi_topological_sort_nodes(graph, heads)
196
195
 
@@ -1061,7 +1060,7 @@ class RegionIdentifier(Analysis):
1061
1060
  assert node_mommy not in graph
1062
1061
  assert node_kiddie not in graph
1063
1062
 
1064
- def _ensure_jump_at_loop_exit_ends(self, node: Union[Block, MultiNode]) -> None:
1063
+ def _ensure_jump_at_loop_exit_ends(self, node: Block | MultiNode) -> None:
1065
1064
  if isinstance(node, Block):
1066
1065
  if not node.statements:
1067
1066
  node.statements.append(
@@ -1,5 +1,4 @@
1
1
  # pylint:disable=no-self-use,arguments-renamed,isinstance-second-argument-not-valid-type
2
- from typing import Optional
3
2
 
4
3
  import ailment
5
4
  import claripy
@@ -19,7 +18,7 @@ class CascadingConditionTransformer(SequenceWalker):
19
18
  ConditionNode: self._handle_Condition,
20
19
  }
21
20
  super().__init__(handlers)
22
- self.cascading_if_node: Optional[CascadingConditionNode] = None
21
+ self.cascading_if_node: CascadingConditionNode | None = None
23
22
 
24
23
  self.walk(node)
25
24
 
@@ -1,6 +1,7 @@
1
1
  # pylint:disable=missing-class-docstring,unused-argument
2
2
  from collections import defaultdict
3
- from typing import Optional, Any, Dict, Set, Tuple, Iterable, Union, DefaultDict, TYPE_CHECKING
3
+ from typing import Optional, Any, DefaultDict, TYPE_CHECKING
4
+ from collections.abc import Iterable
4
5
 
5
6
  import ailment
6
7
  from ailment import Expression, Block, AILBlockWalker
@@ -95,7 +96,7 @@ class ConditionLocation(LocationBase):
95
96
  "case_idx",
96
97
  )
97
98
 
98
- def __init__(self, cond_node_addr, case_idx: Optional[int] = None):
99
+ def __init__(self, cond_node_addr, case_idx: int | None = None):
99
100
  self.node_addr = cond_node_addr
100
101
  self.case_idx = case_idx
101
102
 
@@ -139,7 +140,7 @@ class MultiStatementExpressionAssignmentFinder(AILBlockWalker):
139
140
  self._stmt_handler = stmt_handler
140
141
 
141
142
  def _handle_MultiStatementExpression(
142
- self, expr_idx, expr: "MultiStatementExpression", stmt_idx: int, stmt: Statement, block: Optional[Block]
143
+ self, expr_idx, expr: "MultiStatementExpression", stmt_idx: int, stmt: Statement, block: Block | None
143
144
  ):
144
145
  for idx, stmt_ in enumerate(expr.stmts):
145
146
  self._stmt_handler(idx, stmt_, block)
@@ -174,11 +175,11 @@ class ExpressionUseFinder(AILBlockWalker):
174
175
 
175
176
  def __init__(self):
176
177
  super().__init__()
177
- self.uses: DefaultDict[SimVariable, Set[Tuple[Expression, Optional[ExpressionLocation]]]] = defaultdict(set)
178
+ self.uses: DefaultDict[SimVariable, set[tuple[Expression, ExpressionLocation | None]]] = defaultdict(set)
178
179
  self.has_load = False
179
180
 
180
181
  def _handle_expr(
181
- self, expr_idx: int, expr: Expression, stmt_idx: int, stmt: Optional[Statement], block: Optional[Block]
182
+ self, expr_idx: int, expr: Expression, stmt_idx: int, stmt: Statement | None, block: Block | None
182
183
  ) -> Any:
183
184
  if isinstance(expr, ailment.Register) and expr.variable is not None:
184
185
  if not (isinstance(stmt, ailment.Stmt.Assignment) and stmt.dst is expr):
@@ -189,9 +190,7 @@ class ExpressionUseFinder(AILBlockWalker):
189
190
  return None
190
191
  return super()._handle_expr(expr_idx, expr, stmt_idx, stmt, block)
191
192
 
192
- def _handle_Load(
193
- self, expr_idx: int, expr: ailment.Expr.Load, stmt_idx: int, stmt: Statement, block: Optional[Block]
194
- ):
193
+ def _handle_Load(self, expr_idx: int, expr: ailment.Expr.Load, stmt_idx: int, stmt: Statement, block: Block | None):
195
194
  self.has_load = True
196
195
  return super()._handle_Load(expr_idx, expr, stmt_idx, stmt, block)
197
196
 
@@ -213,8 +212,8 @@ class ExpressionCounter(SequenceWalker):
213
212
  # each element in the set is a tuple of (source of the assignment statement, a tuple of unified variables that
214
213
  # the current assignment depends on, StatementLocation of the assignment statement, a Boolean variable that
215
214
  # indicates if ExpressionUseFinder has succeeded or not)
216
- self.assignments: DefaultDict[Any, Set[Tuple]] = defaultdict(set)
217
- self.uses: Dict[SimVariable, Set[Tuple[Expression, Optional[LocationBase]]]] = {}
215
+ self.assignments: DefaultDict[Any, set[tuple]] = defaultdict(set)
216
+ self.uses: dict[SimVariable, set[tuple[Expression, LocationBase | None]]] = {}
218
217
  self._variable_manager: "VariableManagerInternal" = variable_manager
219
218
 
220
219
  super().__init__(handlers)
@@ -227,7 +226,7 @@ class ExpressionCounter(SequenceWalker):
227
226
 
228
227
  return self._variable_manager.unified_variable(v)
229
228
 
230
- def _handle_Statement(self, idx: int, stmt: ailment.Stmt, node: Union[ailment.Block, LoopNode]):
229
+ def _handle_Statement(self, idx: int, stmt: ailment.Stmt, node: ailment.Block | LoopNode):
231
230
  if isinstance(stmt, ailment.Stmt.Assignment):
232
231
  if isinstance(stmt.dst, ailment.Expr.Register) and stmt.dst.variable is not None:
233
232
  u = self._u(stmt.dst.variable)
@@ -331,7 +330,7 @@ class ExpressionCounter(SequenceWalker):
331
330
 
332
331
 
333
332
  class ExpressionReplacer(AILBlockWalker):
334
- def __init__(self, assignments: Dict, uses: Dict, variable_manager):
333
+ def __init__(self, assignments: dict, uses: dict, variable_manager):
335
334
  super().__init__()
336
335
  self._assignments = assignments
337
336
  self._uses = uses
@@ -344,7 +343,7 @@ class ExpressionReplacer(AILBlockWalker):
344
343
  return self._variable_manager.unified_variable(v)
345
344
 
346
345
  def _handle_MultiStatementExpression(
347
- self, expr_idx, expr: "MultiStatementExpression", stmt_idx: int, stmt: Statement, block: Optional[Block]
346
+ self, expr_idx, expr: "MultiStatementExpression", stmt_idx: int, stmt: Statement, block: Block | None
348
347
  ):
349
348
  changed = False
350
349
  new_statements = []
@@ -385,7 +384,7 @@ class ExpressionReplacer(AILBlockWalker):
385
384
  return expr_
386
385
  return None
387
386
 
388
- def _handle_Assignment(self, stmt_idx: int, stmt: Assignment, block: Optional[Block]):
387
+ def _handle_Assignment(self, stmt_idx: int, stmt: Assignment, block: Block | None):
389
388
  # override the base handler and make sure we do not replace .dst with a Call expression or an ITE expression
390
389
  changed = False
391
390
 
@@ -410,7 +409,7 @@ class ExpressionReplacer(AILBlockWalker):
410
409
  return None
411
410
 
412
411
  def _handle_expr(
413
- self, expr_idx: int, expr: Expression, stmt_idx: int, stmt: Optional[Statement], block: Optional[Block]
412
+ self, expr_idx: int, expr: Expression, stmt_idx: int, stmt: Statement | None, block: Block | None
414
413
  ) -> Any:
415
414
  if isinstance(expr, ailment.Register) and expr.variable is not None:
416
415
  unified_var = self._u(expr.variable)
@@ -421,7 +420,7 @@ class ExpressionReplacer(AILBlockWalker):
421
420
 
422
421
 
423
422
  class ExpressionFolder(SequenceWalker):
424
- def __init__(self, assignments: Dict, uses: Dict, node, variable_manager):
423
+ def __init__(self, assignments: dict, uses: dict, node, variable_manager):
425
424
  handlers = {
426
425
  ailment.Block: self._handle_Block,
427
426
  ConditionNode: self._handle_Condition,
@@ -530,7 +529,7 @@ class StoreStatementFinder(SequenceWalker):
530
529
  This class overrides _handle_Sequence() and _handle_MultiNode() to ensure they traverse nodes from top to bottom.
531
530
  """
532
531
 
533
- def __init__(self, node, intervals: Iterable[Tuple[StatementLocation, LocationBase]]):
532
+ def __init__(self, node, intervals: Iterable[tuple[StatementLocation, LocationBase]]):
534
533
  handlers = {
535
534
  ConditionNode: self._handle_Condition,
536
535
  CascadingConditionNode: self._handle_CascadingCondition,
@@ -540,9 +539,9 @@ class StoreStatementFinder(SequenceWalker):
540
539
 
541
540
  self._intervals = intervals
542
541
 
543
- self._start_to_ends: DefaultDict[StatementLocation, Set[LocationBase]] = defaultdict(set)
544
- self._end_to_starts: DefaultDict[LocationBase, Set[StatementLocation]] = defaultdict(set)
545
- self.interval_to_hasstore: Dict[Tuple[StatementLocation, StatementLocation], bool] = {}
542
+ self._start_to_ends: DefaultDict[StatementLocation, set[LocationBase]] = defaultdict(set)
543
+ self._end_to_starts: DefaultDict[LocationBase, set[StatementLocation]] = defaultdict(set)
544
+ self.interval_to_hasstore: dict[tuple[StatementLocation, StatementLocation], bool] = {}
546
545
  for start, end in intervals:
547
546
  self._start_to_ends[start].add(end)
548
547
  self._end_to_starts[end].add(start)
@@ -1,5 +1,4 @@
1
1
  # pylint:disable=unused-argument,arguments-differ
2
- from typing import Set, Union
3
2
  import logging
4
3
 
5
4
  import ailment
@@ -47,7 +46,7 @@ class GotoSimplifier(SequenceWalker):
47
46
  self.irreducible_gotos = set()
48
47
 
49
48
  super().__init__(handlers)
50
- self._node_addrs: Set[int] = NodeAddressFinder(node).addrs
49
+ self._node_addrs: set[int] = NodeAddressFinder(node).addrs
51
50
 
52
51
  self.walk(node)
53
52
 
@@ -156,7 +155,7 @@ class GotoSimplifier(SequenceWalker):
156
155
  self._handle_irreducible_goto(block, last_stmt, branch_target=False)
157
156
 
158
157
  def _handle_irreducible_goto(
159
- self, block, goto_stmt: Union[ailment.Stmt.Jump, ailment.Stmt.ConditionalJump], branch_target=None
158
+ self, block, goto_stmt: ailment.Stmt.Jump | ailment.Stmt.ConditionalJump, branch_target=None
160
159
  ):
161
160
  if not self._function:
162
161
  l.debug("Unable to store a goto at %#x because simplifier is kb or functionless", block.addr)
@@ -1,6 +1,5 @@
1
1
  # pylint:disable=unused-argument,arguments-differ
2
2
  from collections import defaultdict
3
- from typing import Dict, List
4
3
 
5
4
  import ailment
6
5
 
@@ -36,7 +35,7 @@ class LoopSimplifier(SequenceWalker):
36
35
 
37
36
  super().__init__(handlers)
38
37
  self.functions = functions
39
- self.continue_preludes: Dict[LoopNode, List[ailment.Block]] = defaultdict(list)
38
+ self.continue_preludes: dict[LoopNode, list[ailment.Block]] = defaultdict(list)
40
39
  self.walk(node)
41
40
 
42
41
  @staticmethod
@@ -1,5 +1,4 @@
1
1
  # pylint:disable=unused-argument,arguments-differ
2
- from typing import Set
3
2
 
4
3
  import ailment
5
4
 
@@ -16,7 +15,7 @@ class NodeAddressFinder(SequenceWalker):
16
15
  ailment.Block: self._handle_Block,
17
16
  }
18
17
  super().__init__(handlers=handlers)
19
- self.addrs: Set[int] = set()
18
+ self.addrs: set[int] = set()
20
19
 
21
20
  self.walk(node)
22
21
 
@@ -1,5 +1,3 @@
1
- from typing import Optional
2
-
3
1
  import ailment
4
2
 
5
3
  from ..goto_manager import GotoManager
@@ -31,7 +29,7 @@ class RegionSimplifier(Analysis):
31
29
  self._simplify_switches = simplify_switches
32
30
  self._should_simplify_ifelses = simplify_ifelse
33
31
 
34
- self.goto_manager: Optional[GotoManager] = None
32
+ self.goto_manager: GotoManager | None = None
35
33
  self.result = None
36
34
 
37
35
  self._simplify()
@@ -1,6 +1,6 @@
1
1
  # pylint:disable=no-self-use,arguments-renamed
2
2
  import enum
3
- from typing import DefaultDict, Any, List, Union, Dict, Tuple, Set, Optional
3
+ from typing import DefaultDict, Any
4
4
  from collections import OrderedDict, defaultdict
5
5
 
6
6
  import ailment
@@ -36,7 +36,7 @@ class ConditionalRegion:
36
36
  "parent",
37
37
  )
38
38
 
39
- def __init__(self, variable, op: CmpOp, value: int, node: Union[ConditionNode, ailment.Block], parent=None):
39
+ def __init__(self, variable, op: CmpOp, value: int, node: ConditionNode | ailment.Block, parent=None):
40
40
  self.variable = variable
41
41
  self.op = op
42
42
  self.value = value
@@ -80,8 +80,8 @@ class SwitchClusterFinder(SequenceWalker):
80
80
  }
81
81
  super().__init__(handlers)
82
82
 
83
- self.var2condnodes: DefaultDict[Any, List[ConditionalRegion]] = defaultdict(list)
84
- self.var2switches: DefaultDict[Any, List[SwitchCaseRegion]] = defaultdict(list)
83
+ self.var2condnodes: DefaultDict[Any, list[ConditionalRegion]] = defaultdict(list)
84
+ self.var2switches: DefaultDict[Any, list[SwitchCaseRegion]] = defaultdict(list)
85
85
 
86
86
  self.walk(node)
87
87
 
@@ -103,7 +103,7 @@ class SwitchClusterFinder(SequenceWalker):
103
103
  self.var2switches[variable].append(scr)
104
104
  return super()._handle_SwitchCase(node, parent=parent, **kwargs)
105
105
 
106
- def _process_condition(self, cond: ailment.Expr.Expression, node: Union[ConditionNode, ailment.Block], parent):
106
+ def _process_condition(self, cond: ailment.Expr.Expression, node: ConditionNode | ailment.Block, parent):
107
107
  negated = False
108
108
  if isinstance(cond, ailment.Expr.UnaryOp) and cond.op == "Not":
109
109
  negated = True
@@ -173,7 +173,7 @@ class SwitchClusterReplacer(SequenceWalker):
173
173
  return super()._handle_Condition(node, **kwargs)
174
174
 
175
175
 
176
- def is_simple_jump_node(node, case_addrs, targets: Optional[Set[int]] = None) -> bool:
176
+ def is_simple_jump_node(node, case_addrs, targets: set[int] | None = None) -> bool:
177
177
  if isinstance(node, (SequenceNode, MultiNode)):
178
178
  return all(is_simple_jump_node(nn, case_addrs) for nn in node.nodes)
179
179
  if isinstance(node, ailment.Block):
@@ -213,7 +213,7 @@ def is_simple_jump_node(node, case_addrs, targets: Optional[Set[int]] = None) ->
213
213
  return False
214
214
 
215
215
 
216
- def filter_cond_regions(cond_regions: List[ConditionalRegion], case_addrs: Set[int]) -> List[ConditionalRegion]:
216
+ def filter_cond_regions(cond_regions: list[ConditionalRegion], case_addrs: set[int]) -> list[ConditionalRegion]:
217
217
  """
218
218
  Remove all conditional regions that cannot be merged into switch(es).
219
219
  """
@@ -242,8 +242,8 @@ def filter_cond_regions(cond_regions: List[ConditionalRegion], case_addrs: Set[i
242
242
 
243
243
 
244
244
  def update_switch_case_list(
245
- cases: List[Tuple[Union[int, Tuple[int, ...]], SequenceNode]],
246
- old_case_id: Union[int, Tuple[int, ...]],
245
+ cases: list[tuple[int | tuple[int, ...], SequenceNode]],
246
+ old_case_id: int | tuple[int, ...],
247
247
  new_case_id: int,
248
248
  ) -> None:
249
249
  """
@@ -265,7 +265,7 @@ def update_switch_case_list(
265
265
 
266
266
 
267
267
  def simplify_switch_clusters(
268
- region, var2condnodes: Dict[Any, List[ConditionalRegion]], var2switches: Dict[Any, List[SwitchCaseRegion]]
268
+ region, var2condnodes: dict[Any, list[ConditionalRegion]], var2switches: dict[Any, list[SwitchCaseRegion]]
269
269
  ):
270
270
  """
271
271
  Identify switch clusters and simplify each of them.
@@ -284,7 +284,7 @@ def simplify_switch_clusters(
284
284
  continue
285
285
 
286
286
  # each switch region belongs to a conditional region
287
- switch_region_to_parent_region: Dict[SwitchCaseRegion, Tuple[ConditionalRegion, str]] = {}
287
+ switch_region_to_parent_region: dict[SwitchCaseRegion, tuple[ConditionalRegion, str]] = {}
288
288
  used_condnodes_and_branch = set()
289
289
  for r in switch_regions:
290
290
  for cr in cond_regions:
@@ -337,20 +337,20 @@ def simplify_switch_clusters(
337
337
  used_condnodes = list(condnode for condnode, _ in used_condnodes_and_branch)
338
338
 
339
339
  # collect addresses for all case nodes
340
- case_addr_to_case_id: Dict[int, Union[int, Tuple[int, ...], str]] = {}
340
+ case_addr_to_case_id: dict[int, int | tuple[int, ...] | str] = {}
341
341
  for sr in switch_regions:
342
342
  for case_id, case_node in sr.node.cases.items():
343
343
  case_addr_to_case_id[case_node.addr] = case_id
344
344
  if sr.node.default_node is not None:
345
345
  case_addr_to_case_id[sr.node.default_node.addr] = "default"
346
- case_addrs: Set[int] = set(case_addr_to_case_id)
346
+ case_addrs: set[int] = set(case_addr_to_case_id)
347
347
 
348
348
  # filter cond_regions
349
349
  mergeable_cond_regions = filter_cond_regions(cond_regions, case_addrs)
350
350
 
351
351
  # list all unmatched conditional nodes
352
- standalone_condnodes: List[Tuple[ConditionalRegion, str]] = []
353
- standalone_condjumps: List[ConditionalRegion] = []
352
+ standalone_condnodes: list[tuple[ConditionalRegion, str]] = []
353
+ standalone_condjumps: list[ConditionalRegion] = []
354
354
  for cr in mergeable_cond_regions:
355
355
  if isinstance(cr.node, ConditionNode):
356
356
  if cr.node.true_node is not None and (cr, "true") not in used_condnodes_and_branch:
@@ -487,7 +487,7 @@ def simplify_switch_clusters(
487
487
  continue
488
488
 
489
489
 
490
- def simplify_lowered_switches(region: SequenceNode, var2condnodes: Dict[Any, List[ConditionalRegion]], functions):
490
+ def simplify_lowered_switches(region: SequenceNode, var2condnodes: dict[Any, list[ConditionalRegion]], functions):
491
491
  """
492
492
  Identify a lowered switch and simplify it into a switch-case if possible.
493
493
 
@@ -522,8 +522,8 @@ def simplify_lowered_switches_core(
522
522
  return False
523
523
 
524
524
  caseno_to_node = {}
525
- default_node_candidates: List[Tuple[BaseNode, BaseNode]] = [] # parent to default node candidate
526
- stack: List[(ConditionNode, int, int)] = [(outermost_node, 0, 0xFFFF_FFFF_FFFF_FFFF)]
525
+ default_node_candidates: list[tuple[BaseNode, BaseNode]] = [] # parent to default node candidate
526
+ stack: list[(ConditionNode, int, int)] = [(outermost_node, 0, 0xFFFF_FFFF_FFFF_FFFF)]
527
527
  while stack:
528
528
  node, min_, max_ = stack.pop(0)
529
529
  if node not in node_to_condnode:
@@ -632,7 +632,7 @@ class FindFirstNodeInSet(SequenceWalker):
632
632
  Find the first node out of a set of node appearing in a SequenceNode (and its tree).
633
633
  """
634
634
 
635
- def __init__(self, node_set: Set[BaseNode]):
635
+ def __init__(self, node_set: set[BaseNode]):
636
636
  super().__init__(update_seqnode_in_place=False, force_forward_scan=True)
637
637
  self.node_set = node_set
638
638
  self.first_node = None