angr 9.2.134__py3-none-manylinux2014_aarch64.whl → 9.2.136__py3-none-manylinux2014_aarch64.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 (173) hide show
  1. angr/__init__.py +1 -1
  2. angr/analyses/__init__.py +5 -8
  3. angr/analyses/analysis.py +4 -0
  4. angr/analyses/backward_slice.py +1 -2
  5. angr/analyses/binary_optimizer.py +3 -4
  6. angr/analyses/bindiff.py +4 -6
  7. angr/analyses/boyscout.py +1 -3
  8. angr/analyses/callee_cleanup_finder.py +4 -4
  9. angr/analyses/calling_convention/__init__.py +6 -0
  10. angr/analyses/{calling_convention.py → calling_convention/calling_convention.py} +32 -64
  11. angr/analyses/calling_convention/fact_collector.py +502 -0
  12. angr/analyses/calling_convention/utils.py +57 -0
  13. angr/analyses/cdg.py +1 -2
  14. angr/analyses/cfg/cfb.py +1 -3
  15. angr/analyses/cfg/cfg.py +2 -2
  16. angr/analyses/cfg/cfg_base.py +37 -35
  17. angr/analyses/cfg/cfg_emulated.py +1 -1
  18. angr/analyses/cfg/cfg_fast.py +62 -15
  19. angr/analyses/cfg/cfg_fast_soot.py +1 -1
  20. angr/analyses/cfg/indirect_jump_resolvers/__init__.py +2 -0
  21. angr/analyses/cfg/indirect_jump_resolvers/const_resolver.py +46 -10
  22. angr/analyses/cfg/indirect_jump_resolvers/default_resolvers.py +5 -1
  23. angr/analyses/cfg/indirect_jump_resolvers/jumptable.py +50 -14
  24. angr/analyses/cfg/indirect_jump_resolvers/memload_resolver.py +81 -0
  25. angr/analyses/cfg/indirect_jump_resolvers/propagator_utils.py +24 -5
  26. angr/analyses/cfg/indirect_jump_resolvers/x86_pe_iat.py +2 -5
  27. angr/analyses/complete_calling_conventions.py +32 -3
  28. angr/analyses/congruency_check.py +2 -3
  29. angr/analyses/data_dep/data_dependency_analysis.py +2 -2
  30. angr/analyses/ddg.py +1 -4
  31. angr/analyses/decompiler/ail_simplifier.py +3 -4
  32. angr/analyses/decompiler/clinic.py +42 -7
  33. angr/analyses/decompiler/optimization_passes/duplication_reverter/ail_merge_graph.py +2 -2
  34. angr/analyses/decompiler/optimization_passes/duplication_reverter/duplication_reverter.py +2 -2
  35. angr/analyses/decompiler/optimization_passes/ite_region_converter.py +1 -1
  36. angr/analyses/decompiler/optimization_passes/lowered_switch_simplifier.py +1 -1
  37. angr/analyses/decompiler/optimization_passes/register_save_area_simplifier.py +0 -6
  38. angr/analyses/decompiler/optimization_passes/stack_canary_simplifier.py +2 -7
  39. angr/analyses/decompiler/optimization_passes/switch_default_case_duplicator.py +0 -6
  40. angr/analyses/decompiler/optimization_passes/win_stack_canary_simplifier.py +0 -6
  41. angr/analyses/decompiler/structuring/phoenix.py +1 -1
  42. angr/analyses/disassembly.py +5 -5
  43. angr/analyses/fcp/__init__.py +4 -0
  44. angr/analyses/fcp/fcp.py +429 -0
  45. angr/analyses/identifier/identify.py +1 -3
  46. angr/analyses/loopfinder.py +4 -3
  47. angr/analyses/patchfinder.py +1 -1
  48. angr/analyses/propagator/engine_base.py +4 -3
  49. angr/analyses/propagator/propagator.py +14 -53
  50. angr/analyses/reassembler.py +1 -2
  51. angr/analyses/s_propagator.py +1 -3
  52. angr/analyses/soot_class_hierarchy.py +1 -2
  53. angr/analyses/stack_pointer_tracker.py +18 -2
  54. angr/analyses/static_hooker.py +1 -2
  55. angr/analyses/typehoon/simple_solver.py +2 -2
  56. angr/analyses/variable_recovery/engine_vex.py +5 -0
  57. angr/analyses/variable_recovery/variable_recovery_fast.py +1 -2
  58. angr/analyses/veritesting.py +4 -7
  59. angr/analyses/vfg.py +1 -1
  60. angr/analyses/vsa_ddg.py +1 -2
  61. angr/block.py +3 -2
  62. angr/callable.py +1 -3
  63. angr/calling_conventions.py +15 -7
  64. angr/codenode.py +5 -1
  65. angr/concretization_strategies/__init__.py +1 -83
  66. angr/concretization_strategies/any.py +2 -1
  67. angr/concretization_strategies/any_named.py +1 -1
  68. angr/concretization_strategies/base.py +81 -0
  69. angr/concretization_strategies/controlled_data.py +2 -1
  70. angr/concretization_strategies/eval.py +2 -1
  71. angr/concretization_strategies/logging.py +3 -1
  72. angr/concretization_strategies/max.py +2 -1
  73. angr/concretization_strategies/nonzero.py +2 -1
  74. angr/concretization_strategies/nonzero_range.py +2 -1
  75. angr/concretization_strategies/norepeats.py +2 -1
  76. angr/concretization_strategies/norepeats_range.py +2 -1
  77. angr/concretization_strategies/range.py +2 -1
  78. angr/concretization_strategies/signed_add.py +2 -1
  79. angr/concretization_strategies/single.py +2 -1
  80. angr/concretization_strategies/solutions.py +2 -1
  81. angr/concretization_strategies/unlimited_range.py +2 -1
  82. angr/engines/__init__.py +8 -5
  83. angr/engines/engine.py +3 -5
  84. angr/engines/failure.py +4 -5
  85. angr/engines/procedure.py +5 -7
  86. angr/engines/soot/expressions/__init__.py +22 -23
  87. angr/engines/soot/expressions/base.py +4 -4
  88. angr/engines/soot/expressions/invoke.py +1 -2
  89. angr/engines/soot/statements/__init__.py +9 -10
  90. angr/engines/soot/values/__init__.py +9 -10
  91. angr/engines/soot/values/arrayref.py +3 -3
  92. angr/engines/soot/values/instancefieldref.py +3 -2
  93. angr/engines/successors.py +7 -6
  94. angr/engines/syscall.py +4 -6
  95. angr/engines/unicorn.py +3 -2
  96. angr/engines/vex/claripy/ccall.py +8 -10
  97. angr/engines/vex/claripy/datalayer.py +4 -5
  98. angr/exploration_techniques/__init__.py +0 -2
  99. angr/exploration_techniques/spiller.py +1 -3
  100. angr/exploration_techniques/stochastic.py +2 -3
  101. angr/factory.py +3 -9
  102. angr/knowledge_plugins/cfg/cfg_model.py +20 -17
  103. angr/knowledge_plugins/functions/function.py +74 -77
  104. angr/knowledge_plugins/functions/function_manager.py +14 -7
  105. angr/knowledge_plugins/functions/function_parser.py +1 -1
  106. angr/knowledge_plugins/functions/soot_function.py +16 -16
  107. angr/knowledge_plugins/propagations/propagation_model.py +4 -5
  108. angr/knowledge_plugins/propagations/states.py +0 -511
  109. angr/procedures/libc/memcpy.py +4 -4
  110. angr/procedures/procedure_dict.py +3 -2
  111. angr/protos/__init__.py +2 -5
  112. angr/protos/cfg_pb2.py +21 -18
  113. angr/protos/function_pb2.py +17 -14
  114. angr/protos/primitives_pb2.py +44 -39
  115. angr/protos/variables_pb2.py +36 -31
  116. angr/protos/xrefs_pb2.py +15 -12
  117. angr/sim_procedure.py +15 -16
  118. angr/sim_variable.py +13 -1
  119. angr/simos/__init__.py +2 -0
  120. angr/simos/javavm.py +4 -6
  121. angr/simos/xbox.py +32 -0
  122. angr/state_plugins/__init__.py +0 -2
  123. angr/state_plugins/callstack.py +4 -4
  124. angr/state_plugins/cgc.py +3 -2
  125. angr/state_plugins/gdb.py +6 -5
  126. angr/state_plugins/globals.py +1 -2
  127. angr/state_plugins/heap/heap_brk.py +1 -2
  128. angr/state_plugins/history.py +10 -12
  129. angr/state_plugins/inspect.py +3 -5
  130. angr/state_plugins/libc.py +2 -2
  131. angr/state_plugins/log.py +8 -10
  132. angr/state_plugins/loop_data.py +1 -2
  133. angr/state_plugins/posix.py +7 -7
  134. angr/state_plugins/preconstrainer.py +2 -3
  135. angr/state_plugins/scratch.py +5 -8
  136. angr/state_plugins/sim_action.py +3 -3
  137. angr/state_plugins/solver.py +8 -3
  138. angr/state_plugins/symbolizer.py +5 -4
  139. angr/state_plugins/uc_manager.py +3 -3
  140. angr/state_plugins/unicorn_engine.py +5 -1
  141. angr/state_plugins/view.py +3 -5
  142. angr/storage/file.py +3 -5
  143. angr/storage/memory_mixins/address_concretization_mixin.py +2 -2
  144. angr/storage/memory_mixins/bvv_conversion_mixin.py +3 -3
  145. angr/storage/memory_mixins/clouseau_mixin.py +1 -3
  146. angr/storage/memory_mixins/name_resolution_mixin.py +1 -3
  147. angr/storage/memory_mixins/paged_memory/paged_memory_mixin.py +13 -15
  148. angr/storage/memory_mixins/paged_memory/pages/__init__.py +1 -22
  149. angr/storage/memory_mixins/paged_memory/pages/base.py +31 -0
  150. angr/storage/memory_mixins/paged_memory/pages/list_page.py +1 -1
  151. angr/storage/memory_mixins/paged_memory/pages/mv_list_page.py +1 -1
  152. angr/storage/memory_mixins/paged_memory/pages/ultra_page.py +2 -4
  153. angr/storage/memory_mixins/paged_memory/privileged_mixin.py +3 -4
  154. angr/storage/memory_mixins/regioned_memory/abstract_merger_mixin.py +4 -2
  155. angr/storage/memory_mixins/smart_find_mixin.py +1 -1
  156. angr/storage/memory_mixins/underconstrained_mixin.py +1 -1
  157. angr/storage/memory_mixins/unwrapper_mixin.py +1 -3
  158. angr/utils/bits.py +13 -0
  159. angr/utils/enums_conv.py +28 -12
  160. angr/utils/segment_list.py +25 -22
  161. angr/utils/timing.py +18 -1
  162. angr/vaults.py +5 -6
  163. {angr-9.2.134.dist-info → angr-9.2.136.dist-info}/METADATA +6 -6
  164. {angr-9.2.134.dist-info → angr-9.2.136.dist-info}/RECORD +168 -164
  165. {angr-9.2.134.dist-info → angr-9.2.136.dist-info}/WHEEL +1 -1
  166. angr/analyses/propagator/outdated_definition_walker.py +0 -159
  167. angr/analyses/propagator/tmpvar_finder.py +0 -18
  168. angr/engines/concrete.py +0 -180
  169. angr/exploration_techniques/symbion.py +0 -80
  170. angr/state_plugins/concrete.py +0 -295
  171. {angr-9.2.134.dist-info → angr-9.2.136.dist-info}/LICENSE +0 -0
  172. {angr-9.2.134.dist-info → angr-9.2.136.dist-info}/entry_points.txt +0 -0
  173. {angr-9.2.134.dist-info → angr-9.2.136.dist-info}/top_level.txt +0 -0
@@ -1,20 +1,21 @@
1
+ # pylint:disable=too-many-boolean-expressions
1
2
  from __future__ import annotations
2
3
  import os
3
4
  import logging
4
- import networkx
5
5
  import itertools
6
6
  from collections import defaultdict
7
7
  from collections.abc import Iterable
8
+ import contextlib
9
+ from typing import overload
8
10
 
11
+ import networkx
9
12
  from itanium_demangler import parse
10
13
 
11
14
  from cle.backends.symbol import Symbol
12
15
  from archinfo.arch_arm import get_real_address_if_arm
13
16
  import claripy
14
17
 
15
- from angr.block import Block
16
18
  from angr.knowledge_plugins.cfg.memory_data import MemoryDataSort
17
-
18
19
  from angr.codenode import CodeNode, BlockNode, HookNode, SyscallNode
19
20
  from angr.serializable import Serializable
20
21
  from angr.errors import AngrValueError, SimEngineError, SimMemoryError
@@ -23,14 +24,12 @@ from angr.procedures.definitions import SimSyscallLibrary
23
24
  from angr.protos import function_pb2
24
25
  from angr.calling_conventions import DEFAULT_CC, default_cc
25
26
  from angr.misc.ux import deprecated
26
- from .function_parser import FunctionParser
27
-
28
- l = logging.getLogger(name=__name__)
29
-
30
27
  from angr.sim_type import SimTypeFunction, parse_defns
31
28
  from angr.calling_conventions import SimCC
32
29
  from angr.project import Project
33
- import contextlib
30
+ from .function_parser import FunctionParser
31
+
32
+ l = logging.getLogger(name=__name__)
34
33
 
35
34
 
36
35
  class Function(Serializable):
@@ -42,7 +41,6 @@ class Function(Serializable):
42
41
  "_addr_to_block_node",
43
42
  "_argument_registers",
44
43
  "_argument_stack_variables",
45
- "_block_cache",
46
44
  "_block_sizes",
47
45
  "_call_sites",
48
46
  "_callout_sites",
@@ -159,7 +157,6 @@ class Function(Serializable):
159
157
  # function, it may not be removed from _addr_to_block_node. if you want to list
160
158
  # all blocks of a function, access .blocks.
161
159
  self._block_sizes = {} # map addresses to block sizes
162
- self._block_cache = {} # a cache of real, hard data Block objects
163
160
  self._local_blocks = {} # a dict of all blocks inside the function
164
161
  self._local_block_addrs = set() # a set of addresses of all blocks inside the function
165
162
 
@@ -375,13 +372,6 @@ class Function(Serializable):
375
372
  :param byte_string:
376
373
  :return:
377
374
  """
378
- if addr in self._block_cache:
379
- b = self._block_cache[addr]
380
- if size is None or b.size == size:
381
- return b
382
- # size seems to be updated. remove this cached entry from the block cache
383
- del self._block_cache[addr]
384
-
385
375
  if size is None and addr in self.block_addrs:
386
376
  # we know the size
387
377
  size = self._block_sizes[addr]
@@ -390,7 +380,6 @@ class Function(Serializable):
390
380
  if size is None:
391
381
  # update block_size dict
392
382
  self._block_sizes[addr] = block.size
393
- self._block_cache[addr] = block
394
383
  return block
395
384
 
396
385
  # compatibility
@@ -403,7 +392,7 @@ class Function(Serializable):
403
392
  def nodes(self) -> Iterable[CodeNode]:
404
393
  return self.transition_graph.nodes()
405
394
 
406
- def get_node(self, addr) -> Block:
395
+ def get_node(self, addr) -> BlockNode | None:
407
396
  return self._addr_to_block_node.get(addr, None)
408
397
 
409
398
  @property
@@ -441,7 +430,7 @@ class Function(Serializable):
441
430
 
442
431
  @classmethod
443
432
  def _get_cmsg(cls):
444
- return function_pb2.Function()
433
+ return function_pb2.Function() # pylint:disable=no-member
445
434
 
446
435
  def serialize_to_cmessage(self):
447
436
  return FunctionParser.serialize(self)
@@ -614,7 +603,6 @@ class Function(Serializable):
614
603
  d["_local_transition_graph"] = None
615
604
  d["_project"] = None
616
605
  d["_function_manager"] = None
617
- d["_block_cache"] = {}
618
606
  return d
619
607
 
620
608
  @property
@@ -643,7 +631,7 @@ class Function(Serializable):
643
631
 
644
632
  @property
645
633
  def size(self):
646
- return sum([b.size for b in self.blocks])
634
+ return sum(b.size for b in self.blocks)
647
635
 
648
636
  @property
649
637
  def binary(self):
@@ -676,7 +664,7 @@ class Function(Serializable):
676
664
  dec = self.project.analyses.Decompiler(self, cfg=self._function_manager._kb.cfgs.get_most_accurate())
677
665
  return dec.codegen.text
678
666
 
679
- def add_jumpout_site(self, node):
667
+ def add_jumpout_site(self, node: CodeNode):
680
668
  """
681
669
  Add a custom jumpout site.
682
670
 
@@ -684,11 +672,11 @@ class Function(Serializable):
684
672
  :return: None
685
673
  """
686
674
 
687
- self._register_nodes(True, node)
675
+ node = self._register_node(True, node)
688
676
  self._jumpout_sites.add(node)
689
677
  self._add_endpoint(node, "transition")
690
678
 
691
- def add_retout_site(self, node):
679
+ def add_retout_site(self, node: CodeNode):
692
680
  """
693
681
  Add a custom retout site.
694
682
 
@@ -704,7 +692,7 @@ class Function(Serializable):
704
692
  :return: None
705
693
  """
706
694
 
707
- self._register_nodes(True, node)
695
+ node = self._register_node(True, node)
708
696
  self._retout_sites.add(node)
709
697
  self._add_endpoint(node, "return")
710
698
 
@@ -786,7 +774,6 @@ class Function(Serializable):
786
774
  return None
787
775
 
788
776
  def _clear_transition_graph(self):
789
- self._block_cache = {}
790
777
  self._block_sizes = {}
791
778
  self._addr_to_block_node = {}
792
779
  self._local_blocks = {}
@@ -813,11 +800,13 @@ class Function(Serializable):
813
800
 
814
801
  # it's confirmed. register the node if needed
815
802
  if "outside" not in data or data["outside"] is False:
816
- self._register_nodes(True, dst)
803
+ dst = self._register_node(True, dst)
817
804
 
818
805
  self.transition_graph[src][dst]["confirmed"] = True
819
806
 
820
- def _transit_to(self, from_node, to_node, outside=False, ins_addr=None, stmt_idx=None, is_exception=False):
807
+ def _transit_to(
808
+ self, from_node: CodeNode, to_node, outside=False, ins_addr=None, stmt_idx=None, is_exception=False
809
+ ):
821
810
  """
822
811
  Registers an edge between basic blocks in this function's transition graph.
823
812
  Arguments are CodeNode objects.
@@ -831,16 +820,15 @@ class Function(Serializable):
831
820
  """
832
821
 
833
822
  if outside:
834
- self._register_nodes(True, from_node)
823
+ from_node = self._register_node(True, from_node)
835
824
  if to_node is not None:
836
- self._register_nodes(False, to_node)
825
+ to_node = self._register_node(False, to_node)
837
826
 
838
827
  self._jumpout_sites.add(from_node)
839
828
  else:
829
+ from_node = self._register_node(True, from_node)
840
830
  if to_node is not None:
841
- self._register_nodes(True, from_node, to_node)
842
- else:
843
- self._register_nodes(True, from_node)
831
+ to_node = self._register_node(True, to_node)
844
832
 
845
833
  type_ = "transition" if not is_exception else "exception"
846
834
  if to_node is not None:
@@ -872,19 +860,22 @@ class Function(Serializable):
872
860
  :type ins_addr: int or None
873
861
  """
874
862
 
875
- self._register_nodes(True, from_node)
863
+ from_node = self._register_node(True, from_node)
876
864
 
877
865
  if to_func.is_syscall:
878
866
  self.transition_graph.add_edge(from_node, to_func, type="syscall", stmt_idx=stmt_idx, ins_addr=ins_addr)
879
867
  else:
880
868
  self.transition_graph.add_edge(from_node, to_func, type="call", stmt_idx=stmt_idx, ins_addr=ins_addr)
881
869
  if ret_node is not None:
870
+ ret_node = self._register_node(return_to_outside is False, ret_node)
882
871
  self._fakeret_to(from_node, ret_node, to_outside=return_to_outside)
883
872
 
884
873
  self._local_transition_graph = None
885
874
 
886
875
  def _fakeret_to(self, from_node, to_node, confirmed=None, to_outside=False):
887
- self._register_nodes(True, from_node)
876
+ from_node = self._register_node(True, from_node)
877
+ if confirmed:
878
+ to_node = self._register_node(not to_outside, to_node)
888
879
 
889
880
  if confirmed is None:
890
881
  self.transition_graph.add_edge(from_node, to_node, type="fake_return", outside=to_outside)
@@ -892,8 +883,6 @@ class Function(Serializable):
892
883
  self.transition_graph.add_edge(
893
884
  from_node, to_node, type="fake_return", confirmed=confirmed, outside=to_outside
894
885
  )
895
- if confirmed:
896
- self._register_nodes(not to_outside, to_node)
897
886
 
898
887
  self._local_transition_graph = None
899
888
 
@@ -911,45 +900,56 @@ class Function(Serializable):
911
900
  self._local_transition_graph = None
912
901
 
913
902
  def _update_local_blocks(self, node: CodeNode):
914
- self._local_blocks[node.addr] = node
915
- self._local_block_addrs.add(node.addr)
903
+ if node.addr not in self._local_blocks or self._local_blocks[node.addr] != node:
904
+ self._local_blocks[node.addr] = node
905
+ self._local_block_addrs.add(node.addr)
916
906
 
917
907
  def _update_addr_to_block_cache(self, node: BlockNode):
918
908
  if node.addr not in self._addr_to_block_node:
919
909
  self._addr_to_block_node[node.addr] = node
920
910
 
921
- def _register_nodes(self, is_local, *nodes):
922
- if not isinstance(is_local, bool):
923
- raise AngrValueError('_register_nodes(): the "is_local" parameter must be a bool')
924
-
925
- for node in nodes:
926
- if node.addr not in self:
927
- # only add each node once
928
- self.transition_graph.add_node(node)
929
-
930
- if not isinstance(node, CodeNode):
931
- continue
932
- node._graph = self.transition_graph
933
- if self._block_sizes.get(node.addr, 0) == 0:
934
- self._block_sizes[node.addr] = node.size
935
- if node.addr == self.addr and (self.startpoint is None or not self.startpoint.is_hook):
936
- self.startpoint = node
937
- if is_local and node.addr not in self._local_blocks:
938
- self._update_local_blocks(node)
939
- # add BlockNodes to the addr_to_block_node cache if not already there
940
- if isinstance(node, BlockNode):
941
- self._update_addr_to_block_cache(node)
942
- # else:
943
- # # checks that we don't have multiple block nodes at a single address
944
- # assert node == self._addr_to_block_node[node.addr]
945
-
946
- def _add_return_site(self, return_site):
911
+ @overload
912
+ def _register_node(self, is_local: bool, node: CodeNode) -> CodeNode: ...
913
+
914
+ @overload
915
+ def _register_node(self, is_local: bool, node: Function) -> Function: ...
916
+
917
+ def _register_node(self, is_local: bool, node: CodeNode | Function) -> CodeNode | Function:
918
+ # if the node already exists and is the same, we reuse the existing node
919
+ if is_local and self._local_blocks.get(node.addr, None) == node:
920
+ return self._local_blocks[node.addr]
921
+
922
+ if node.addr not in self and node not in self.transition_graph:
923
+ # only add each node to the graph once
924
+ self.transition_graph.add_node(node)
925
+
926
+ if not isinstance(node, CodeNode):
927
+ # function and other things bail here
928
+ return node
929
+
930
+ # this is either a new node or a different node at the same address
931
+ node._graph = self.transition_graph
932
+ if self._block_sizes.get(node.addr, 0) == 0:
933
+ self._block_sizes[node.addr] = node.size
934
+ if node.addr == self.addr and (self.startpoint is None or not self.startpoint.is_hook):
935
+ self.startpoint = node
936
+ if is_local and node.addr not in self._local_blocks:
937
+ self._update_local_blocks(node)
938
+ # add BlockNodes to the addr_to_block_node cache if not already there
939
+ if isinstance(node, BlockNode):
940
+ self._update_addr_to_block_cache(node)
941
+ # else:
942
+ # # checks that we don't have multiple block nodes at a single address
943
+ # assert node == self._addr_to_block_node[node.addr]
944
+ return node
945
+
946
+ def _add_return_site(self, return_site: CodeNode):
947
947
  """
948
948
  Registers a basic block as a site for control flow to return from this function.
949
949
 
950
- :param CodeNode return_site: The block node that ends with a return.
950
+ :param return_site: The block node that ends with a return.
951
951
  """
952
- self._register_nodes(True, return_site)
952
+ return_site = self._register_node(True, return_site)
953
953
 
954
954
  self._ret_sites.add(return_site)
955
955
  # A return site must be an endpoint of the function - you cannot continue execution of the current function
@@ -1036,8 +1036,9 @@ class Function(Serializable):
1036
1036
  if function.returning is False:
1037
1037
  # the target function does not return
1038
1038
  the_node = self.get_node(src.addr)
1039
- self._callout_sites.add(the_node)
1040
- self._add_endpoint(the_node, "call")
1039
+ if the_node is not None:
1040
+ self._callout_sites.add(the_node)
1041
+ self._add_endpoint(the_node, "call")
1041
1042
 
1042
1043
  def get_call_sites(self) -> Iterable[int]:
1043
1044
  """
@@ -1285,8 +1286,8 @@ class Function(Serializable):
1285
1286
  """
1286
1287
  Draw the graph and save it to a PNG file.
1287
1288
  """
1288
- import matplotlib.pyplot as pyplot # pylint: disable=import-error
1289
- from networkx.drawing.nx_agraph import graphviz_layout # pylint: disable=import-error
1289
+ import matplotlib.pyplot as pyplot # pylint: disable=import-error,import-outside-toplevel
1290
+ from networkx.drawing.nx_agraph import graphviz_layout # pylint: disable=import-error,import-outside-toplevel
1290
1291
 
1291
1292
  tmp_graph = networkx.classes.digraph.DiGraph()
1292
1293
  for from_block, to_block in self.transition_graph.edges():
@@ -1416,11 +1417,8 @@ class Function(Serializable):
1416
1417
  self._local_blocks[n.addr] = new_node
1417
1418
 
1418
1419
  # update block_cache and block_sizes
1419
- if (n.addr in self._block_cache and self._block_cache[n.addr].size != new_node.size) or (
1420
- n.addr in self._block_sizes and self._block_sizes[n.addr] != new_node.size
1421
- ):
1420
+ if n.addr in self._block_sizes and self._block_sizes[n.addr] != new_node.size:
1422
1421
  # the cache needs updating
1423
- self._block_cache.pop(n.addr, None)
1424
1422
  self._block_sizes[n.addr] = new_node.size
1425
1423
 
1426
1424
  for p, _, data in original_predecessors:
@@ -1680,7 +1678,6 @@ class Function(Serializable):
1680
1678
  func.startpoint = self.startpoint
1681
1679
  func._addr_to_block_node = self._addr_to_block_node.copy()
1682
1680
  func._block_sizes = self._block_sizes.copy()
1683
- func._block_cache = self._block_cache.copy()
1684
1681
  func._local_blocks = self._local_blocks.copy()
1685
1682
  func._local_block_addrs = self._local_block_addrs.copy()
1686
1683
  func.info = self.info.copy()
@@ -6,6 +6,7 @@ from collections.abc import Generator
6
6
  import logging
7
7
  import collections.abc
8
8
  import re
9
+ import weakref
9
10
  from sortedcontainers import SortedDict
10
11
 
11
12
  import networkx
@@ -31,7 +32,7 @@ class FunctionDict(SortedDict):
31
32
  """
32
33
 
33
34
  def __init__(self, backref, *args, **kwargs):
34
- self._backref = backref
35
+ self._backref = weakref.proxy(backref) if backref is not None else None
35
36
  self._key_types = kwargs.pop("key_types", int)
36
37
  super().__init__(*args, **kwargs)
37
38
 
@@ -39,7 +40,7 @@ class FunctionDict(SortedDict):
39
40
  try:
40
41
  return super().__getitem__(addr)
41
42
  except KeyError as ex:
42
- if not isinstance(addr, self._key_types):
43
+ if isinstance(addr, bool) or not isinstance(addr, self._key_types):
43
44
  raise TypeError(f"FunctionDict only supports {self._key_types} as key type") from ex
44
45
 
45
46
  if isinstance(addr, SootMethodDescriptor):
@@ -148,7 +149,7 @@ class FunctionManager(KnowledgeBasePlugin, collections.abc.Mapping):
148
149
  dst_func = self._function_map[function_addr]
149
150
  if syscall in (True, False):
150
151
  dst_func.is_syscall = syscall
151
- dst_func._register_nodes(True, node)
152
+ dst_func._register_node(True, node)
152
153
  self.block_map[node.addr] = node
153
154
 
154
155
  def _add_call_to(
@@ -160,7 +161,7 @@ class FunctionManager(KnowledgeBasePlugin, collections.abc.Mapping):
160
161
  syscall=None,
161
162
  stmt_idx=None,
162
163
  ins_addr=None,
163
- return_to_outside=False,
164
+ return_to_outside: bool = False,
164
165
  ):
165
166
  """
166
167
  Add a call to a function.
@@ -172,7 +173,7 @@ class FunctionManager(KnowledgeBasePlugin, collections.abc.Mapping):
172
173
  :param bool syscall: If this is a call to a syscall or not.
173
174
  :param int stmt_idx: ID of the statement where this call happens.
174
175
  :param int ins_addr: Address of the instruction where this call happens.
175
- :param bool return_to_outside: True if the return of the call is considered going to outside of the current
176
+ :param return_to_outside: True if the return of the call is considered going to outside of the current
176
177
  function.
177
178
  :return: None
178
179
  """
@@ -306,7 +307,7 @@ class FunctionManager(KnowledgeBasePlugin, collections.abc.Mapping):
306
307
  try:
307
308
  _ = self[item]
308
309
  return True
309
- except KeyError:
310
+ except (KeyError, TypeError):
310
311
  return False
311
312
 
312
313
  def __getitem__(self, k) -> Function:
@@ -406,7 +407,7 @@ class FunctionManager(KnowledgeBasePlugin, collections.abc.Mapping):
406
407
 
407
408
  try:
408
409
  prev_addr = self._function_map.floor_addr(addr)
409
- return self._function_map[prev_addr]
410
+ return self._function_map.get(prev_addr)
410
411
 
411
412
  except KeyError:
412
413
  return None
@@ -460,6 +461,12 @@ class FunctionManager(KnowledgeBasePlugin, collections.abc.Mapping):
460
461
  :rtype: Function or None
461
462
  """
462
463
  if name is not None and name.startswith("sub_"):
464
+ # first check if a function with the specified name exists
465
+ for func in self.get_by_name(name, check_previous_names=check_previous_names):
466
+ if plt is None or func.is_plt == plt:
467
+ return func
468
+
469
+ # then enter the syntactic sugar mode
463
470
  try:
464
471
  addr = int(name.split("_")[-1], 16)
465
472
  name = None
@@ -246,7 +246,7 @@ class FunctionParser:
246
246
  # add leftover blocks
247
247
  for block in blocks.values():
248
248
  if block not in added_nodes:
249
- obj._register_nodes(True, block)
249
+ obj._register_node(True, block)
250
250
 
251
251
  return obj
252
252
 
@@ -108,24 +108,24 @@ class SootFunction(Function):
108
108
  # The Shimple CFG is already normalized.
109
109
  pass
110
110
 
111
- def _register_nodes(self, is_local, *nodes):
112
- if not isinstance(is_local, bool):
113
- raise AngrValueError('_register_nodes(): the "is_local" parameter must be a bool')
111
+ def _register_node(self, is_local: bool, node):
112
+ if is_local and self._local_blocks.get(node.addr) == node:
113
+ return self._local_blocks[node.addr]
114
114
 
115
- for node in nodes:
115
+ if node not in self.transition_graph:
116
116
  self.transition_graph.add_node(node)
117
- node._graph = self.transition_graph
118
- if node.addr not in self or self._block_sizes[node.addr] == 0:
119
- self._block_sizes[node.addr] = node.size
120
- if node.addr == self.addr.addr and (self.startpoint is None or not self.startpoint.is_hook):
121
- self.startpoint = node
122
- if is_local:
123
- self._local_blocks[node.addr] = node
124
- self._local_block_addrs.add(node.addr)
125
- # add BlockNodes to the addr_to_block_node cache if not already there
126
- if isinstance(node, BlockNode) and node.addr not in self._addr_to_block_node:
127
- self._addr_to_block_node[node.addr] = node
117
+ node._graph = self.transition_graph
118
+ if node.addr not in self or self._block_sizes[node.addr] == 0:
119
+ self._block_sizes[node.addr] = node.size
120
+ if node.addr == self.addr.addr and (self.startpoint is None or not self.startpoint.is_hook):
121
+ self.startpoint = node
122
+ if is_local:
123
+ self._local_blocks[node.addr] = node
124
+ self._local_block_addrs.add(node.addr)
125
+ # add BlockNodes to the addr_to_block_node cache if not already there
126
+ if isinstance(node, BlockNode) and node.addr not in self._addr_to_block_node:
127
+ self._addr_to_block_node[node.addr] = node
128
+ return node
128
129
 
129
130
 
130
131
  from angr.codenode import BlockNode
131
- from angr.errors import AngrValueError
@@ -6,7 +6,7 @@ import claripy
6
6
  import ailment
7
7
  from angr.serializable import Serializable
8
8
  from angr.knowledge_plugins.functions.function import Function
9
- from .states import PropagatorVEXState, PropagatorAILState, PropagatorState
9
+ from .states import PropagatorVEXState, PropagatorState
10
10
 
11
11
 
12
12
  class PropagationModel(Serializable):
@@ -65,10 +65,9 @@ class PropagationModel(Serializable):
65
65
  preds = [self.states[pnode.addr] for pnode in self._function.graph.predecessors(node)]
66
66
  if not preds:
67
67
  if isinstance(node, ailment.Block):
68
- state = PropagatorAILState.initial_state(self._function.project, func_addr=self._function.addr)
69
- else:
70
- state = PropagatorVEXState.initial_state(self._function.project, func_addr=self._function.addr)
71
- state.store_register(state.arch.ip_offset, state.arch.bytes, claripy.BVV(block_addr, state.arch.bits))
68
+ raise NotImplementedError
69
+ state = PropagatorVEXState.initial_state(self._function.project, func_addr=self._function.addr)
70
+ state.store_register(state.arch.ip_offset, state.arch.bytes, claripy.BVV(block_addr, state.arch.bits))
72
71
  else:
73
72
  state, _ = preds[0].merge(*preds[1:])
74
73
  return state