angr 9.2.102__py3-none-manylinux2014_x86_64.whl → 9.2.103__py3-none-manylinux2014_x86_64.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 (239) 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/misc/ansi.py +1 -2
  179. angr/misc/autoimport.py +3 -3
  180. angr/misc/plugins.py +9 -9
  181. angr/procedures/definitions/__init__.py +16 -16
  182. angr/procedures/definitions/linux_kernel.py +1 -1
  183. angr/procedures/definitions/parse_win32json.py +1 -1
  184. angr/procedures/java_jni/__init__.py +1 -1
  185. angr/procedures/java_jni/array_operations.py +1 -2
  186. angr/procedures/java_jni/method_calls.py +1 -2
  187. angr/procedures/posix/inet_ntoa.py +1 -2
  188. angr/procedures/stubs/format_parser.py +3 -3
  189. angr/project.py +13 -11
  190. angr/sim_manager.py +12 -12
  191. angr/sim_procedure.py +7 -3
  192. angr/sim_state.py +2 -2
  193. angr/sim_type.py +60 -45
  194. angr/sim_variable.py +5 -5
  195. angr/simos/simos.py +1 -2
  196. angr/simos/userland.py +1 -2
  197. angr/state_plugins/callstack.py +3 -2
  198. angr/state_plugins/history.py +1 -2
  199. angr/state_plugins/solver.py +34 -34
  200. angr/storage/memory_mixins/__init__.py +4 -3
  201. angr/storage/memory_mixins/actions_mixin.py +1 -3
  202. angr/storage/memory_mixins/address_concretization_mixin.py +1 -3
  203. angr/storage/memory_mixins/convenient_mappings_mixin.py +3 -4
  204. angr/storage/memory_mixins/default_filler_mixin.py +1 -1
  205. angr/storage/memory_mixins/label_merger_mixin.py +2 -2
  206. angr/storage/memory_mixins/multi_value_merger_mixin.py +4 -3
  207. angr/storage/memory_mixins/paged_memory/page_backer_mixins.py +9 -8
  208. angr/storage/memory_mixins/paged_memory/paged_memory_mixin.py +12 -11
  209. angr/storage/memory_mixins/paged_memory/pages/cooperation.py +8 -8
  210. angr/storage/memory_mixins/paged_memory/pages/history_tracking_mixin.py +2 -3
  211. angr/storage/memory_mixins/paged_memory/pages/list_page.py +10 -11
  212. angr/storage/memory_mixins/paged_memory/pages/multi_values.py +11 -10
  213. angr/storage/memory_mixins/paged_memory/pages/mv_list_page.py +18 -17
  214. angr/storage/memory_mixins/paged_memory/pages/ultra_page.py +12 -11
  215. angr/storage/memory_mixins/regioned_memory/abstract_address_descriptor.py +3 -3
  216. angr/storage/memory_mixins/regioned_memory/abstract_merger_mixin.py +3 -2
  217. angr/storage/memory_mixins/regioned_memory/region_data.py +1 -2
  218. angr/storage/memory_mixins/regioned_memory/region_meta_mixin.py +2 -2
  219. angr/storage/memory_mixins/regioned_memory/regioned_address_concretization_mixin.py +3 -3
  220. angr/storage/memory_mixins/regioned_memory/regioned_memory_mixin.py +18 -21
  221. angr/storage/memory_mixins/size_resolution_mixin.py +1 -2
  222. angr/storage/memory_mixins/symbolic_merger_mixin.py +3 -2
  223. angr/storage/memory_mixins/top_merger_mixin.py +3 -2
  224. angr/storage/memory_object.py +2 -4
  225. angr/utils/algo.py +3 -2
  226. angr/utils/dynamic_dictlist.py +5 -5
  227. angr/utils/formatting.py +4 -4
  228. angr/utils/funcid.py +1 -2
  229. angr/utils/graph.py +5 -6
  230. angr/utils/library.py +5 -5
  231. angr/utils/mp.py +5 -4
  232. angr/utils/segment_list.py +3 -4
  233. angr/utils/typing.py +3 -2
  234. {angr-9.2.102.dist-info → angr-9.2.103.dist-info}/METADATA +9 -11
  235. {angr-9.2.102.dist-info → angr-9.2.103.dist-info}/RECORD +239 -236
  236. {angr-9.2.102.dist-info → angr-9.2.103.dist-info}/LICENSE +0 -0
  237. {angr-9.2.102.dist-info → angr-9.2.103.dist-info}/WHEEL +0 -0
  238. {angr-9.2.102.dist-info → angr-9.2.103.dist-info}/entry_points.txt +0 -0
  239. {angr-9.2.102.dist-info → angr-9.2.103.dist-info}/top_level.txt +0 -0
@@ -1,5 +1,6 @@
1
1
  # pylint:disable=line-too-long,import-outside-toplevel,import-error,multiple-statements,too-many-boolean-expressions
2
- from typing import List, Dict, Tuple, Union, Set, Any, DefaultDict, Optional, OrderedDict as ODict, TYPE_CHECKING
2
+ from typing import Any, DefaultDict, Optional, TYPE_CHECKING
3
+ from collections import OrderedDict as ODict
3
4
  from collections import defaultdict, OrderedDict
4
5
  from enum import Enum
5
6
  import logging
@@ -80,7 +81,7 @@ class PhoenixStructurer(StructurerBase):
80
81
  parent_map=None,
81
82
  condition_processor=None,
82
83
  func: Optional["Function"] = None,
83
- case_entry_to_switch_head: Optional[Dict[int, int]] = None,
84
+ case_entry_to_switch_head: dict[int, int] | None = None,
84
85
  parent_region=None,
85
86
  improve_structurer=True,
86
87
  use_multistmtexprs: MultiStmtExprMode = MultiStmtExprMode.MAX_ONE_CALL,
@@ -101,14 +102,14 @@ class PhoenixStructurer(StructurerBase):
101
102
  # structuring cycles.
102
103
  # the set is populated during the analysis. _last_resort_refinement() will ensure not to remove any edges
103
104
  # who fall into these sets.
104
- self.whitelist_edges: Set[Tuple[int, int]] = set()
105
+ self.whitelist_edges: set[tuple[int, int]] = set()
105
106
  # also whitelist certain nodes that are definitely header for switch-case constructs. they should not be merged
106
107
  # into another node before we successfully structure the entire switch-case.
107
- self.switch_case_known_heads: Set[Block] = set()
108
+ self.switch_case_known_heads: set[Block] = set()
108
109
 
109
110
  # whitelist certain nodes that should be treated as a tail node for do-whiles. these nodes should not be
110
111
  # absorbed into other SequenceNodes
111
- self.dowhile_known_tail_nodes: Set = set()
112
+ self.dowhile_known_tail_nodes: set = set()
112
113
 
113
114
  self._phoenix_improved = self._improve_structurer
114
115
  self._edge_virtualization_hints = []
@@ -266,7 +267,7 @@ class PhoenixStructurer(StructurerBase):
266
267
  self._rewrite_jumps_to_continues(loop_node.sequence_node)
267
268
  return matched
268
269
 
269
- def _match_cyclic_while(self, node, head, graph, full_graph) -> Tuple[bool, Optional[LoopNode], Optional[BaseNode]]:
270
+ def _match_cyclic_while(self, node, head, graph, full_graph) -> tuple[bool, LoopNode | None, BaseNode | None]:
270
271
  succs = list(full_graph.successors(node))
271
272
  if len(succs) == 2:
272
273
  left, right = succs
@@ -406,7 +407,7 @@ class PhoenixStructurer(StructurerBase):
406
407
 
407
408
  def _match_cyclic_while_with_single_successor(
408
409
  self, node, head, graph, full_graph
409
- ) -> Tuple[bool, Optional[LoopNode], Optional[BaseNode]]:
410
+ ) -> tuple[bool, LoopNode | None, BaseNode | None]:
410
411
  if self._region.successors:
411
412
  return False, None, None
412
413
  if node is not head:
@@ -474,9 +475,7 @@ class PhoenixStructurer(StructurerBase):
474
475
 
475
476
  return True, loop_node, successor_node
476
477
 
477
- def _match_cyclic_dowhile(
478
- self, node, head, graph, full_graph
479
- ) -> Tuple[bool, Optional[LoopNode], Optional[BaseNode]]:
478
+ def _match_cyclic_dowhile(self, node, head, graph, full_graph) -> tuple[bool, LoopNode | None, BaseNode | None]:
480
479
  preds = list(full_graph.predecessors(node))
481
480
  succs = list(full_graph.successors(node))
482
481
  if ((node is head and len(preds) >= 1) or len(preds) >= 2) and len(succs) == 1:
@@ -543,7 +542,7 @@ class PhoenixStructurer(StructurerBase):
543
542
  return True, loop_node, succ
544
543
  return False, None, None
545
544
 
546
- def _match_cyclic_natural_loop(self, node, head, graph, full_graph) -> Tuple[bool, Optional[LoopNode]]:
545
+ def _match_cyclic_natural_loop(self, node, head, graph, full_graph) -> tuple[bool, LoopNode | None]:
547
546
  if not (node is head or graph.in_degree[node] == 2):
548
547
  return False, None
549
548
 
@@ -609,8 +608,8 @@ class PhoenixStructurer(StructurerBase):
609
608
  is_while, result_while = self._refine_cyclic_is_while_loop(graph, fullgraph, loop_head, head_succs)
610
609
  is_dowhile, result_dowhile = self._refine_cyclic_is_dowhile_loop(graph, fullgraph, loop_head, head_succs)
611
610
 
612
- continue_edges: List[Tuple[BaseNode, BaseNode]] = []
613
- outgoing_edges: List = []
611
+ continue_edges: list[tuple[BaseNode, BaseNode]] = []
612
+ outgoing_edges: list = []
614
613
 
615
614
  if is_while and is_dowhile:
616
615
  # gotta pick one!
@@ -872,7 +871,7 @@ class PhoenixStructurer(StructurerBase):
872
871
 
873
872
  def _refine_cyclic_is_while_loop(
874
873
  self, graph, fullgraph, loop_head, head_succs
875
- ) -> Tuple[bool, Optional[Tuple[List, List, BaseNode, BaseNode]]]:
874
+ ) -> tuple[bool, tuple[list, list, BaseNode, BaseNode] | None]:
876
875
  if len(head_succs) == 2 and any(head_succ not in graph for head_succ in head_succs):
877
876
  # make sure the head_pred is not already structured
878
877
  _, _, head_block_0 = self._find_node_going_to_dst(loop_head, head_succs[0])
@@ -880,7 +879,7 @@ class PhoenixStructurer(StructurerBase):
880
879
  if head_block_0 is head_block_1 and head_block_0 is not None:
881
880
  # there is an out-going edge from the loop head
882
881
  # virtualize all other edges
883
- continue_edges: List[Tuple[BaseNode, BaseNode]] = []
882
+ continue_edges: list[tuple[BaseNode, BaseNode]] = []
884
883
  outgoing_edges = []
885
884
  successor = next(iter(head_succ for head_succ in head_succs if head_succ not in graph))
886
885
  for node in networkx.descendants(graph, loop_head):
@@ -897,7 +896,7 @@ class PhoenixStructurer(StructurerBase):
897
896
 
898
897
  def _refine_cyclic_is_dowhile_loop( # pylint:disable=unused-argument
899
898
  self, graph, fullgraph, loop_head, head_succs
900
- ) -> Tuple[bool, Optional[Tuple[List, List, BaseNode, BaseNode]]]:
899
+ ) -> tuple[bool, tuple[list, list, BaseNode, BaseNode] | None]:
901
900
  # check if there is an out-going edge from the loop tail
902
901
  head_preds = list(fullgraph.predecessors(loop_head))
903
902
  if len(head_preds) == 1:
@@ -908,7 +907,7 @@ class PhoenixStructurer(StructurerBase):
908
907
  _, _, src_block_0 = self._find_node_going_to_dst(head_pred, head_pred_succs[0])
909
908
  _, _, src_block_1 = self._find_node_going_to_dst(head_pred, head_pred_succs[1])
910
909
  if src_block_0 is src_block_1 and src_block_0 is not None:
911
- continue_edges: List[Tuple[BaseNode, BaseNode]] = []
910
+ continue_edges: list[tuple[BaseNode, BaseNode]] = []
912
911
  outgoing_edges = []
913
912
  # there is an out-going edge from the loop tail
914
913
  # virtualize all other edges
@@ -1047,7 +1046,7 @@ class PhoenixStructurer(StructurerBase):
1047
1046
 
1048
1047
  # make a fake jumptable
1049
1048
  node_default_addr = None
1050
- case_entries: Dict[int, Tuple[int, Optional[int]]] = {}
1049
+ case_entries: dict[int, tuple[int, int | None]] = {}
1051
1050
  for _, case_value, case_target_addr, case_target_idx, _ in last_stmt.case_addrs:
1052
1051
  if isinstance(case_value, str):
1053
1052
  if case_value == "default":
@@ -1264,7 +1263,7 @@ class PhoenixStructurer(StructurerBase):
1264
1263
  return True
1265
1264
 
1266
1265
  def _match_acyclic_incomplete_switch_cases(
1267
- self, node, graph: networkx.DiGraph, full_graph: networkx.DiGraph, jump_tables: Dict
1266
+ self, node, graph: networkx.DiGraph, full_graph: networkx.DiGraph, jump_tables: dict
1268
1267
  ) -> bool:
1269
1268
  # sanity checks
1270
1269
  if node.addr not in jump_tables:
@@ -1300,14 +1299,14 @@ class PhoenixStructurer(StructurerBase):
1300
1299
 
1301
1300
  def _switch_build_cases(
1302
1301
  self,
1303
- case_and_entryaddrs: Dict[int, Union[int, Tuple[int, Optional[int]]]],
1302
+ case_and_entryaddrs: dict[int, int | tuple[int, int | None]],
1304
1303
  head_node,
1305
1304
  node_a: BaseNode,
1306
1305
  node_b_addr,
1307
1306
  graph,
1308
1307
  full_graph,
1309
- ) -> Tuple[ODict, Any, Set[Any]]:
1310
- cases: ODict[Union[int, Tuple[int]], SequenceNode] = OrderedDict()
1308
+ ) -> tuple[ODict, Any, set[Any]]:
1309
+ cases: ODict[int | tuple[int], SequenceNode] = OrderedDict()
1311
1310
  to_remove = set()
1312
1311
 
1313
1312
  # it is possible that the default node gets duplicated by other analyses and creates a default node (addr.a)
@@ -1315,11 +1314,11 @@ class PhoenixStructurer(StructurerBase):
1315
1314
  # successor to node_a
1316
1315
  default_node_candidates = [nn for nn in graph.nodes if nn.addr == node_b_addr]
1317
1316
  if len(default_node_candidates) == 0:
1318
- node_default: Optional[BaseNode] = None
1317
+ node_default: BaseNode | None = None
1319
1318
  elif len(default_node_candidates) == 1:
1320
- node_default: Optional[BaseNode] = default_node_candidates[0]
1319
+ node_default: BaseNode | None = default_node_candidates[0]
1321
1320
  else:
1322
- node_default: Optional[BaseNode] = next(
1321
+ node_default: BaseNode | None = next(
1323
1322
  iter(nn for nn in default_node_candidates if graph.has_edge(head_node, nn)), None
1324
1323
  )
1325
1324
 
@@ -1331,8 +1330,8 @@ class PhoenixStructurer(StructurerBase):
1331
1330
  node_default = new_node
1332
1331
 
1333
1332
  # entry_addrs_set = set(jumptable_entries)
1334
- converted_nodes: Dict[Tuple[int, Optional[int]], Any] = {}
1335
- entry_addr_to_ids: DefaultDict[Tuple[int, Optional[int]], Set[int]] = defaultdict(set)
1333
+ converted_nodes: dict[tuple[int, int | None], Any] = {}
1334
+ entry_addr_to_ids: DefaultDict[tuple[int, int | None], set[int]] = defaultdict(set)
1336
1335
 
1337
1336
  # the default node might get duplicated (e.g., by EagerReturns). we detect if a duplicate of the default node
1338
1337
  # (node b) is a successor node of node a. we only skip those entries going to the default node if no duplicate
@@ -1420,7 +1419,7 @@ class PhoenixStructurer(StructurerBase):
1420
1419
  node_default_addr: int,
1421
1420
  node_default,
1422
1421
  addr,
1423
- to_remove: Set,
1422
+ to_remove: set,
1424
1423
  graph: networkx.DiGraph,
1425
1424
  full_graph: networkx.DiGraph,
1426
1425
  node_a=None,
@@ -1952,7 +1951,7 @@ class PhoenixStructurer(StructurerBase):
1952
1951
 
1953
1952
  def _match_acyclic_short_circuit_conditions_type_a( # pylint:disable=unused-argument
1954
1953
  self, graph, full_graph, start_node
1955
- ) -> Optional[Tuple]:
1954
+ ) -> tuple | None:
1956
1955
  # if (a) goto right
1957
1956
  # else if (b) goto right
1958
1957
  # else goto other_succ
@@ -1990,7 +1989,7 @@ class PhoenixStructurer(StructurerBase):
1990
1989
 
1991
1990
  def _match_acyclic_short_circuit_conditions_type_b( # pylint:disable=unused-argument
1992
1991
  self, graph, full_graph, start_node
1993
- ) -> Optional[Tuple]:
1992
+ ) -> tuple | None:
1994
1993
  # if (a) goto left
1995
1994
  # right:
1996
1995
  # else if (b) goto left
@@ -2032,7 +2031,7 @@ class PhoenixStructurer(StructurerBase):
2032
2031
 
2033
2032
  def _match_acyclic_short_circuit_conditions_type_c( # pylint:disable=unused-argument
2034
2033
  self, graph, full_graph, start_node
2035
- ) -> Optional[Tuple]:
2034
+ ) -> tuple | None:
2036
2035
  # if (a) goto successor
2037
2036
  # else if (b) goto successor
2038
2037
  # right:
@@ -2070,7 +2069,7 @@ class PhoenixStructurer(StructurerBase):
2070
2069
 
2071
2070
  def _match_acyclic_short_circuit_conditions_type_d( # pylint:disable=unused-argument
2072
2071
  self, graph, full_graph, start_node
2073
- ) -> Optional[Tuple]:
2072
+ ) -> tuple | None:
2074
2073
  # if (a) goto else_node
2075
2074
  # left:
2076
2075
  # else if (b) goto else_node
@@ -2107,7 +2106,7 @@ class PhoenixStructurer(StructurerBase):
2107
2106
  return left, edge_cond_left, right, edge_cond_left_right, else_node
2108
2107
  return None
2109
2108
 
2110
- def _last_resort_refinement(self, head, graph: networkx.DiGraph, full_graph: Optional[networkx.DiGraph]) -> bool:
2109
+ def _last_resort_refinement(self, head, graph: networkx.DiGraph, full_graph: networkx.DiGraph | None) -> bool:
2111
2110
  if self._phoenix_improved:
2112
2111
  while self._edge_virtualization_hints:
2113
2112
  src, dst = self._edge_virtualization_hints.pop(0)
@@ -2228,7 +2227,7 @@ class PhoenixStructurer(StructurerBase):
2228
2227
  if remove_src_last_stmt:
2229
2228
  remove_last_statement(src)
2230
2229
 
2231
- def _should_use_multistmtexprs(self, node: Union[Block, BaseNode]) -> bool:
2230
+ def _should_use_multistmtexprs(self, node: Block | BaseNode) -> bool:
2232
2231
  if self._use_multistmtexprs == MultiStmtExprMode.NEVER:
2233
2232
  return False
2234
2233
  if self._use_multistmtexprs == MultiStmtExprMode.ALWAYS:
@@ -2244,10 +2243,10 @@ class PhoenixStructurer(StructurerBase):
2244
2243
  @staticmethod
2245
2244
  def _find_node_going_to_dst(
2246
2245
  node: SequenceNode,
2247
- dst: Union[Block, BaseNode],
2246
+ dst: Block | BaseNode,
2248
2247
  last=True,
2249
2248
  condjump_only=False,
2250
- ) -> Tuple[Optional[int], Optional[BaseNode], Optional[Block]]:
2249
+ ) -> tuple[int | None, BaseNode | None, Block | None]:
2251
2250
  """
2252
2251
 
2253
2252
  :param node:
@@ -2335,7 +2334,7 @@ class PhoenixStructurer(StructurerBase):
2335
2334
  update_seqnode_in_place=False,
2336
2335
  force_forward_scan=True,
2337
2336
  )
2338
- walker.parent_and_block: List[Tuple[int, Any, Union[Block, MultiNode]]] = []
2337
+ walker.parent_and_block: list[tuple[int, Any, Block | MultiNode]] = []
2339
2338
  walker.block_id = -1
2340
2339
  walker.walk(node)
2341
2340
  if not walker.parent_and_block:
@@ -2385,7 +2384,7 @@ class PhoenixStructurer(StructurerBase):
2385
2384
  graph.add_edge(case_node, succs[0])
2386
2385
 
2387
2386
  @staticmethod
2388
- def _count_statements(node: Union[BaseNode, Block]) -> int:
2387
+ def _count_statements(node: BaseNode | Block) -> int:
2389
2388
  if isinstance(node, Block):
2390
2389
  return sum(1 for stmt in node.statements if not isinstance(stmt, Label))
2391
2390
  elif isinstance(node, MultiNode):
@@ -2395,19 +2394,19 @@ class PhoenixStructurer(StructurerBase):
2395
2394
  return 1
2396
2395
 
2397
2396
  @staticmethod
2398
- def _is_single_statement_block(node: Union[BaseNode, Block]) -> bool:
2397
+ def _is_single_statement_block(node: BaseNode | Block) -> bool:
2399
2398
  if isinstance(node, (Block, MultiNode, SequenceNode)):
2400
2399
  return PhoenixStructurer._count_statements(node) == 1
2401
2400
  return False
2402
2401
 
2403
2402
  @staticmethod
2404
- def _is_sequential_statement_block(node: Union[BaseNode, Block]) -> bool:
2403
+ def _is_sequential_statement_block(node: BaseNode | Block) -> bool:
2405
2404
  """
2406
2405
  Examine if the node can be converted into a MultiStatementExpression object. The conversion fails if there are
2407
2406
  any conditional statements or goto statements before the very last statement of the node.
2408
2407
  """
2409
2408
 
2410
- def _is_sequential_statement_list(stmts: List[Statement]) -> bool:
2409
+ def _is_sequential_statement_list(stmts: list[Statement]) -> bool:
2411
2410
  if not stmts:
2412
2411
  return True
2413
2412
  for stmt in stmts[:-1]:
@@ -2421,7 +2420,7 @@ class PhoenixStructurer(StructurerBase):
2421
2420
  return False
2422
2421
  return True
2423
2422
 
2424
- def _to_statement_list(node: Union[Block, MultiNode, SequenceNode]) -> List[Statement]:
2423
+ def _to_statement_list(node: Block | MultiNode | SequenceNode) -> list[Statement]:
2425
2424
  if isinstance(node, Block):
2426
2425
  return node.statements
2427
2426
  if isinstance(node, MultiNode):
@@ -2444,7 +2443,7 @@ class PhoenixStructurer(StructurerBase):
2444
2443
  return _is_sequential_statement_list(stmt_list)
2445
2444
 
2446
2445
  @staticmethod
2447
- def _build_multistatementexpr_statements(block) -> Optional[List[Statement]]:
2446
+ def _build_multistatementexpr_statements(block) -> list[Statement] | None:
2448
2447
  stmts = []
2449
2448
  if isinstance(block, (SequenceNode, MultiNode)):
2450
2449
  for b in block.nodes:
@@ -2474,7 +2473,7 @@ class PhoenixStructurer(StructurerBase):
2474
2473
  graph.remove_edge(src, succ)
2475
2474
 
2476
2475
  @staticmethod
2477
- def _remove_first_statement_if_jump(node: Union[BaseNode, Block]) -> Optional[Union[Jump, ConditionalJump]]:
2476
+ def _remove_first_statement_if_jump(node: BaseNode | Block) -> Jump | ConditionalJump | None:
2478
2477
  if isinstance(node, Block):
2479
2478
  if node.statements:
2480
2479
  idx = 0
@@ -2503,7 +2502,7 @@ class PhoenixStructurer(StructurerBase):
2503
2502
  return None
2504
2503
 
2505
2504
  @staticmethod
2506
- def _chick_order_edges(edges: List, node_seq: Dict[Any, int]) -> List:
2505
+ def _chick_order_edges(edges: list, node_seq: dict[Any, int]) -> list:
2507
2506
  graph = networkx.DiGraph()
2508
2507
  graph.add_edges_from(edges)
2509
2508
 
@@ -2520,7 +2519,7 @@ class PhoenixStructurer(StructurerBase):
2520
2519
  return list(sorted(edges, key=_sort_edge, reverse=True))
2521
2520
 
2522
2521
  @staticmethod
2523
- def _replace_node_in_edge_list(edge_list: List[Tuple], old_node, new_node) -> None:
2522
+ def _replace_node_in_edge_list(edge_list: list[tuple], old_node, new_node) -> None:
2524
2523
  for idx in range(len(edge_list)): # pylint:disable=consider-using-enumerate
2525
2524
  edge = edge_list[idx]
2526
2525
  src, dst = edge
@@ -1,5 +1,5 @@
1
1
  import itertools
2
- from typing import Optional, Type, Dict, TYPE_CHECKING
2
+ from typing import Optional, TYPE_CHECKING
3
3
  import logging
4
4
 
5
5
  import networkx
@@ -33,7 +33,7 @@ class RecursiveStructurer(Analysis):
33
33
  region,
34
34
  cond_proc=None,
35
35
  func: Optional["Function"] = None,
36
- structurer_cls: Optional[Type] = None,
36
+ structurer_cls: type | None = None,
37
37
  improve_structurer=True,
38
38
  **kwargs,
39
39
  ):
@@ -51,7 +51,7 @@ class RecursiveStructurer(Analysis):
51
51
 
52
52
  def _analyze(self):
53
53
  region = self._region.recursive_copy()
54
- self._case_entry_to_switch_head: Dict[int, int] = self._get_switch_case_entries()
54
+ self._case_entry_to_switch_head: dict[int, int] = self._get_switch_case_entries()
55
55
  self.result_incomplete = False
56
56
 
57
57
  # visit the region in post-order DFS
@@ -149,7 +149,7 @@ class RecursiveStructurer(Analysis):
149
149
  def _replace_region_with_region(parent_region, sub_region, new_region):
150
150
  parent_region.replace_region_with_region(sub_region, new_region)
151
151
 
152
- def _get_switch_case_entries(self) -> Dict[int, int]:
152
+ def _get_switch_case_entries(self) -> dict[int, int]:
153
153
  if self.function is None:
154
154
  return {}
155
155
 
@@ -1,5 +1,6 @@
1
1
  # pylint:disable=unused-argument
2
- from typing import Optional, Dict, Set, List, Any, Union, Tuple, OrderedDict as ODict, TYPE_CHECKING
2
+ from typing import Optional, Any, TYPE_CHECKING
3
+ from collections import OrderedDict as ODict
3
4
  from collections import defaultdict, OrderedDict
4
5
  import logging
5
6
 
@@ -50,7 +51,7 @@ class StructurerBase(Analysis):
50
51
  parent_map=None,
51
52
  condition_processor=None,
52
53
  func: Optional["Function"] = None,
53
- case_entry_to_switch_head: Optional[Dict[int, int]] = None,
54
+ case_entry_to_switch_head: dict[int, int] | None = None,
54
55
  parent_region=None,
55
56
  improve_structurer=True,
56
57
  **kwargs,
@@ -251,7 +252,7 @@ class StructurerBase(Analysis):
251
252
  if len(node.nodes) > 1:
252
253
  for i in range(len(node.nodes) - 1):
253
254
  this_node = node.nodes[i]
254
- jump_stmt: Optional[Union[ailment.Stmt.Jump, ailment.Stmt.ConditionalJump]] = None
255
+ jump_stmt: ailment.Stmt.Jump | ailment.Stmt.ConditionalJump | None = None
255
256
  if (
256
257
  isinstance(this_node, ailment.Block)
257
258
  and this_node.statements
@@ -313,7 +314,7 @@ class StructurerBase(Analysis):
313
314
  if len(node.nodes) > 1:
314
315
  for i in range(len(node.nodes) - 1):
315
316
  this_node = node.nodes[i]
316
- jump_stmt: Optional[Union[ailment.Stmt.Jump, ailment.Stmt.ConditionalJump]] = None
317
+ jump_stmt: ailment.Stmt.Jump | ailment.Stmt.ConditionalJump | None = None
317
318
  if (
318
319
  isinstance(this_node, ailment.Block)
319
320
  and this_node.statements
@@ -387,7 +388,7 @@ class StructurerBase(Analysis):
387
388
  return
388
389
 
389
390
  # stores all nodes that will replace the current AIL Block node
390
- new_nodes: List = []
391
+ new_nodes: list = []
391
392
  last_nonjump_stmt_idx = 0
392
393
 
393
394
  # find all jump and indirect jump statements
@@ -466,7 +467,7 @@ class StructurerBase(Analysis):
466
467
  walker = SequenceWalker(handlers=handlers)
467
468
  walker.walk(loop_node)
468
469
 
469
- def _rewrite_jumps_to_continues(self, loop_seq: SequenceNode, loop_node: Optional[LoopNode] = None):
470
+ def _rewrite_jumps_to_continues(self, loop_seq: SequenceNode, loop_node: LoopNode | None = None):
470
471
  continue_node_addr = loop_seq.addr
471
472
  # exception: do-while with a multi-statement condition
472
473
  if (
@@ -740,12 +741,12 @@ class StructurerBase(Analysis):
740
741
  #
741
742
 
742
743
  def _reorganize_switch_cases(
743
- self, cases: ODict[Union[int, Tuple[int, ...]], SequenceNode]
744
- ) -> ODict[Union[int, Tuple[int, ...]], SequenceNode]:
744
+ self, cases: ODict[int | tuple[int, ...], SequenceNode]
745
+ ) -> ODict[int | tuple[int, ...], SequenceNode]:
745
746
  new_cases = OrderedDict()
746
747
 
747
748
  caseid2gotoaddrs = {}
748
- addr2caseids: Dict[int, List[int, Tuple[int, ...]]] = defaultdict(list)
749
+ addr2caseids: dict[int, list[int, tuple[int, ...]]] = defaultdict(list)
749
750
 
750
751
  # collect goto locations
751
752
  for idx, case_node in cases.items():
@@ -814,8 +815,8 @@ class StructurerBase(Analysis):
814
815
 
815
816
  @staticmethod
816
817
  def _remove_last_statement_if_jump(
817
- node: Union[BaseNode, ailment.Block]
818
- ) -> Optional[Union[ailment.Stmt.Jump, ailment.Stmt.ConditionalJump]]:
818
+ node: BaseNode | ailment.Block,
819
+ ) -> ailment.Stmt.Jump | ailment.Stmt.ConditionalJump | None:
819
820
  try:
820
821
  last_stmts = ConditionProcessor.get_last_statements(node)
821
822
  except EmptyBlockNotice:
@@ -878,7 +879,7 @@ class StructurerBase(Analysis):
878
879
  else:
879
880
  return SequenceNode(addr, nodes=[node_0, node_1])
880
881
 
881
- def _update_new_sequences(self, removed_sequences: Set[SequenceNode], replaced_sequences: Dict[SequenceNode, Any]):
882
+ def _update_new_sequences(self, removed_sequences: set[SequenceNode], replaced_sequences: dict[SequenceNode, Any]):
882
883
  new_sequences = []
883
884
  for new_seq_ in self._new_sequences:
884
885
  if new_seq_ not in removed_sequences:
@@ -917,8 +918,8 @@ class StructurerBase(Analysis):
917
918
  @staticmethod
918
919
  def replace_node_in_node(
919
920
  parent_node: BaseNode,
920
- old_node: Union[BaseNode, ailment.Block],
921
- new_node: Union[BaseNode, ailment.Block],
921
+ old_node: BaseNode | ailment.Block,
922
+ new_node: BaseNode | ailment.Block,
922
923
  ) -> None:
923
924
  if isinstance(parent_node, SequenceNode):
924
925
  for i in range(len(parent_node.nodes)): # pylint:disable=consider-using-enumerate
@@ -941,7 +942,7 @@ class StructurerBase(Analysis):
941
942
  raise TypeError(f"Unsupported node type {type(parent_node)}")
942
943
 
943
944
  @staticmethod
944
- def is_a_jump_target(stmt: Union[ailment.Stmt.ConditionalJump, ailment.Stmt.Jump], addr: int) -> bool:
945
+ def is_a_jump_target(stmt: ailment.Stmt.ConditionalJump | ailment.Stmt.Jump, addr: int) -> bool:
945
946
  if isinstance(stmt, ailment.Stmt.ConditionalJump):
946
947
  if isinstance(stmt.true_target, ailment.Expr.Const) and stmt.true_target.value == addr:
947
948
  return True
@@ -1,5 +1,6 @@
1
1
  # pylint:disable=missing-class-docstring
2
- from typing import List, Tuple, Any, Optional, Union, OrderedDict as ODict
2
+ from typing import Any
3
+ from collections import OrderedDict as ODict
3
4
 
4
5
  import claripy
5
6
  import ailment
@@ -95,7 +96,7 @@ class BaseNode:
95
96
 
96
97
  return True
97
98
 
98
- addr: Optional[int]
99
+ addr: int | None
99
100
 
100
101
  def dbg_repr(self, indent=0):
101
102
  return " " * indent + f"## dbg_repr not implemented for {type(self).__name__}"
@@ -107,7 +108,7 @@ class SequenceNode(BaseNode):
107
108
  "nodes",
108
109
  )
109
110
 
110
- def __init__(self, addr: Optional[int], nodes=None):
111
+ def __init__(self, addr: int | None, nodes=None):
111
112
  self.addr = addr
112
113
  self.nodes = nodes if nodes is not None else []
113
114
 
@@ -237,7 +238,7 @@ class CascadingConditionNode(BaseNode):
237
238
  "else_node",
238
239
  )
239
240
 
240
- def __init__(self, addr, condition_and_nodes: List[Tuple[Any, BaseNode]], else_node: BaseNode = None):
241
+ def __init__(self, addr, condition_and_nodes: list[tuple[Any, BaseNode]], else_node: BaseNode = None):
241
242
  self.addr = addr
242
243
  self.condition_and_nodes = condition_and_nodes
243
244
  self.else_node = else_node
@@ -357,9 +358,9 @@ class SwitchCaseNode(BaseNode):
357
358
  "addr",
358
359
  )
359
360
 
360
- def __init__(self, switch_expr, cases: ODict[Union[int, Tuple[int, ...]], SequenceNode], default_node, addr=None):
361
+ def __init__(self, switch_expr, cases: ODict[int | tuple[int, ...], SequenceNode], default_node, addr=None):
361
362
  self.switch_expr = switch_expr
362
- self.cases: ODict[Union[int, Tuple[int, ...]], SequenceNode] = cases
363
+ self.cases: ODict[int | tuple[int, ...], SequenceNode] = cases
363
364
  self.default_node = default_node
364
365
  self.addr = addr
365
366
 
@@ -372,10 +373,10 @@ class IncompleteSwitchCaseNode(BaseNode):
372
373
 
373
374
  __slots__ = ("addr", "head", "cases")
374
375
 
375
- def __init__(self, addr, head, cases: List):
376
+ def __init__(self, addr, head, cases: list):
376
377
  self.addr = addr
377
378
  self.head = head
378
- self.cases: List = cases
379
+ self.cases: list = cases
379
380
 
380
381
 
381
382
  #
@@ -395,7 +396,7 @@ class IncompleteSwitchCaseHeadStatement(ailment.statement.Statement):
395
396
  self.switch_variable = switch_variable
396
397
  # original cmp node, case value | "default", address of the case node, idx of the case node,
397
398
  # address of the next cmp node
398
- self.case_addrs: List[Tuple[ailment.Block, Union[int, str], int, Optional[int], int]] = case_addrs
399
+ self.case_addrs: list[tuple[ailment.Block, int | str, int, int | None, int]] = case_addrs
399
400
  # a string representation of the addresses of all cases, used for hashing
400
401
  self._case_addrs_str = str(sorted([c[0].addr for c in self.case_addrs if c[0] is not None]))
401
402
 
@@ -1,7 +1,8 @@
1
1
  # pylint:disable=wrong-import-position,broad-exception-caught,ungrouped-imports
2
2
  import pathlib
3
3
  import copy
4
- from typing import Optional, Tuple, Any, Union, List, Iterable
4
+ from typing import Any, Union
5
+ from collections.abc import Iterable
5
6
  import logging
6
7
 
7
8
  import networkx
@@ -119,7 +120,7 @@ def extract_jump_targets(stmt):
119
120
  return targets
120
121
 
121
122
 
122
- def switch_extract_cmp_bounds(last_stmt: ailment.Stmt.ConditionalJump) -> Optional[Tuple[Any, int, int]]:
123
+ def switch_extract_cmp_bounds(last_stmt: ailment.Stmt.ConditionalJump) -> tuple[Any, int, int] | None:
123
124
  """
124
125
  Check the last statement of the switch-case header node, and extract lower+upper bounds for the comparison.
125
126
 
@@ -161,7 +162,7 @@ def get_ast_subexprs(claripy_ast):
161
162
  yield ast
162
163
 
163
164
 
164
- def insert_node(parent, insert_location: str, node, node_idx: Optional[Union[int, Tuple[int]]], label=None):
165
+ def insert_node(parent, insert_location: str, node, node_idx: int | tuple[int] | None, label=None):
165
166
  if insert_location not in {"before", "after"}:
166
167
  raise ValueError('"insert_location" must be either "before" or "after"')
167
168
 
@@ -336,7 +337,7 @@ def has_nonlabel_statements(block: ailment.Block) -> bool:
336
337
  return block.statements and any(not isinstance(stmt, ailment.Stmt.Label) for stmt in block.statements)
337
338
 
338
339
 
339
- def first_nonlabel_statement(block: Union[ailment.Block, "MultiNode"]) -> Optional[ailment.Stmt.Statement]:
340
+ def first_nonlabel_statement(block: Union[ailment.Block, "MultiNode"]) -> ailment.Stmt.Statement | None:
340
341
  if isinstance(block, MultiNode):
341
342
  for n in block.nodes:
342
343
  stmt = first_nonlabel_statement(n)
@@ -350,14 +351,14 @@ def first_nonlabel_statement(block: Union[ailment.Block, "MultiNode"]) -> Option
350
351
  return None
351
352
 
352
353
 
353
- def last_nonlabel_statement(block: ailment.Block) -> Optional[ailment.Stmt.Statement]:
354
+ def last_nonlabel_statement(block: ailment.Block) -> ailment.Stmt.Statement | None:
354
355
  for stmt in reversed(block.statements):
355
356
  if not isinstance(stmt, ailment.Stmt.Label):
356
357
  return stmt
357
358
  return None
358
359
 
359
360
 
360
- def first_nonlabel_node(seq: "SequenceNode") -> Optional[Union["BaseNode", ailment.Block]]:
361
+ def first_nonlabel_node(seq: "SequenceNode") -> Union["BaseNode", ailment.Block] | None:
361
362
  for node in seq.nodes:
362
363
  if isinstance(node, CodeNode):
363
364
  inner_node = node.node
@@ -421,7 +422,7 @@ def structured_node_is_simple_return(node: Union["SequenceNode", "MultiNode"], g
421
422
  Returns true on any block ending in linear statements and a return.
422
423
  """
423
424
 
424
- def _flatten_structured_node(packed_node: Union["SequenceNode", "MultiNode"]) -> List[ailment.Block]:
425
+ def _flatten_structured_node(packed_node: Union["SequenceNode", "MultiNode"]) -> list[ailment.Block]:
425
426
  if not packed_node or not packed_node.nodes:
426
427
  return []
427
428
 
@@ -477,8 +478,8 @@ def peephole_optimize_exprs(block, expr_opts):
477
478
  v = False
478
479
 
479
480
  def _handle_expr(
480
- expr_idx: int, expr: ailment.Expr.Expression, stmt_idx: int, stmt: Optional[ailment.Stmt.Statement], block
481
- ) -> Optional[ailment.Expr.Expression]:
481
+ expr_idx: int, expr: ailment.Expr.Expression, stmt_idx: int, stmt: ailment.Stmt.Statement | None, block
482
+ ) -> ailment.Expr.Expression | None:
482
483
  old_expr = expr
483
484
 
484
485
  redo = True
@@ -510,8 +511,8 @@ def peephole_optimize_exprs(block, expr_opts):
510
511
 
511
512
  def peephole_optimize_expr(expr, expr_opts):
512
513
  def _handle_expr(
513
- expr_idx: int, expr: ailment.Expr.Expression, stmt_idx: int, stmt: Optional[ailment.Stmt.Statement], block
514
- ) -> Optional[ailment.Expr.Expression]:
514
+ expr_idx: int, expr: ailment.Expr.Expression, stmt_idx: int, stmt: ailment.Stmt.Statement | None, block
515
+ ) -> ailment.Expr.Expression | None:
515
516
  old_expr = expr
516
517
 
517
518
  redo = True
@@ -595,7 +596,7 @@ def peephole_optimize_stmts(block, stmt_opts):
595
596
  return statements, any_update
596
597
 
597
598
 
598
- def match_stmt_classes(all_stmts: List, idx: int, stmt_class_seq: Iterable[type]) -> bool:
599
+ def match_stmt_classes(all_stmts: list, idx: int, stmt_class_seq: Iterable[type]) -> bool:
599
600
  for i, cls in enumerate(stmt_class_seq):
600
601
  if idx + i >= len(all_stmts):
601
602
  return False
@@ -639,7 +640,7 @@ def peephole_optimize_multistmts(block, stmt_opts):
639
640
  return statements, any_update
640
641
 
641
642
 
642
- def decompile_functions(path, functions=None, structurer=None, catch_errors=False) -> Optional[str]:
643
+ def decompile_functions(path, functions=None, structurer=None, catch_errors=False) -> str | None:
643
644
  """
644
645
  Decompile a binary into a set of functions.
645
646
 
@@ -663,7 +664,7 @@ def decompile_functions(path, functions=None, structurer=None, catch_errors=Fals
663
664
  functions = list(sorted(cfg.kb.functions))
664
665
 
665
666
  # normalize the functions that could be ints as names
666
- normalized_functions: List[Union[int, str]] = []
667
+ normalized_functions: list[int | str] = []
667
668
  for func in functions:
668
669
  try:
669
670
  if isinstance(func, str):
@@ -742,7 +743,7 @@ def find_block_by_addr(graph: networkx.DiGraph, addr: int):
742
743
  raise KeyError("The block is not in the graph!")
743
744
 
744
745
 
745
- def sequence_to_blocks(seq: "BaseNode") -> List[ailment.Block]:
746
+ def sequence_to_blocks(seq: "BaseNode") -> list[ailment.Block]:
746
747
  """
747
748
  Converts a sequence node (BaseNode) to a list of ailment blocks contained in it and all its children.
748
749
  """
@@ -753,7 +754,7 @@ def sequence_to_blocks(seq: "BaseNode") -> List[ailment.Block]:
753
754
 
754
755
  def sequence_to_statements(
755
756
  seq: "BaseNode", exclude=(ailment.statement.Jump, ailment.statement.Jump)
756
- ) -> List[ailment.statement.Statement]:
757
+ ) -> list[ailment.statement.Statement]:
757
758
  """
758
759
  Converts a sequence node (BaseNode) to a list of ailment Statements contained in it and all its children.
759
760
  May exclude certain types of statements.