angr 9.2.76__py3-none-win_amd64.whl → 9.2.77__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 (37) hide show
  1. angr/__init__.py +1 -1
  2. angr/analyses/cfg/indirect_jump_resolvers/amd64_pe_iat.py +7 -1
  3. angr/analyses/cfg/indirect_jump_resolvers/x86_pe_iat.py +7 -1
  4. angr/analyses/decompiler/clinic.py +4 -1
  5. angr/analyses/decompiler/condition_processor.py +4 -0
  6. angr/analyses/decompiler/optimization_passes/ite_region_converter.py +4 -3
  7. angr/analyses/decompiler/optimization_passes/multi_simplifier.py +1 -1
  8. angr/analyses/decompiler/structured_codegen/c.py +3 -0
  9. angr/analyses/propagator/engine_ail.py +1 -1
  10. angr/analyses/reaching_definitions/engine_ail.py +3 -6
  11. angr/analyses/reaching_definitions/engine_vex.py +32 -2
  12. angr/analyses/reaching_definitions/function_handler.py +1 -1
  13. angr/analyses/reaching_definitions/rd_initializer.py +6 -6
  14. angr/analyses/reaching_definitions/rd_state.py +9 -11
  15. angr/analyses/typehoon/typevars.py +19 -29
  16. angr/analyses/variable_recovery/variable_recovery_fast.py +33 -31
  17. angr/engines/light/engine.py +1 -1
  18. angr/keyed_region.py +19 -3
  19. angr/knowledge_plugins/functions/function.py +8 -0
  20. angr/knowledge_plugins/key_definitions/live_definitions.py +53 -44
  21. angr/knowledge_plugins/key_definitions/liveness.py +102 -34
  22. angr/knowledge_plugins/key_definitions/rd_model.py +4 -4
  23. angr/knowledge_plugins/propagations/states.py +3 -1
  24. angr/knowledge_plugins/variables/variable_manager.py +51 -25
  25. angr/lib/angr_native.dll +0 -0
  26. angr/misc/bug_report.py +2 -2
  27. angr/storage/memory_mixins/__init__.py +3 -2
  28. angr/storage/memory_mixins/paged_memory/paged_memory_multivalue_mixin.py +63 -0
  29. angr/storage/memory_mixins/paged_memory/pages/mv_list_page.py +5 -0
  30. {angr-9.2.76.dist-info → angr-9.2.77.dist-info}/METADATA +6 -6
  31. {angr-9.2.76.dist-info → angr-9.2.77.dist-info}/RECORD +37 -36
  32. tests/analyses/decompiler/test_decompiler.py +5 -1
  33. tests/analyses/test_flirt.py +3 -1
  34. tests/procedures/libc/test_string.py +2 -1
  35. {angr-9.2.76.dist-info → angr-9.2.77.dist-info}/LICENSE +0 -0
  36. {angr-9.2.76.dist-info → angr-9.2.77.dist-info}/WHEEL +0 -0
  37. {angr-9.2.76.dist-info → angr-9.2.77.dist-info}/top_level.txt +0 -0
@@ -370,6 +370,14 @@ class LiveDefinitions:
370
370
  if isinstance(anno, DefinitionAnnotation):
371
371
  yield anno.definition
372
372
 
373
+ @staticmethod
374
+ def extract_defs_from_annotations(annos: Iterable["Annotation"]) -> Set[Definition]:
375
+ defs = set()
376
+ for anno in annos:
377
+ if isinstance(anno, DefinitionAnnotation):
378
+ defs.add(anno.definition)
379
+ return defs
380
+
373
381
  @staticmethod
374
382
  def extract_defs_from_mv(mv: MultiValues) -> Generator[Definition, None, None]:
375
383
  for vs in mv.values():
@@ -614,64 +622,60 @@ class LiveDefinitions:
614
622
 
615
623
  def get_definitions(
616
624
  self, thing: Union[Atom, Definition[Atom], Iterable[Atom], Iterable[Definition[Atom]], MultiValues]
617
- ) -> Iterable[Definition[Atom]]:
625
+ ) -> Set[Definition[Atom]]:
618
626
  if isinstance(thing, MultiValues):
627
+ defs = set()
619
628
  for vs in thing.values():
620
629
  for v in vs:
621
- for anno in v.annotations:
622
- if isinstance(anno, DefinitionAnnotation):
623
- yield anno.definition
624
- return
630
+ defs.update(LiveDefinitions.extract_defs_from_annotations(v.annotations))
631
+ return defs
625
632
  elif isinstance(thing, Atom):
626
633
  pass
627
634
  elif isinstance(thing, Definition):
628
635
  thing = thing.atom
629
636
  else:
637
+ defs = set()
630
638
  for atom2 in thing:
631
- yield from self.get_definitions(atom2)
632
- return
639
+ defs |= self.get_definitions(atom2)
640
+ return defs
633
641
 
634
642
  if isinstance(thing, Register):
635
- yield from self.get_register_definitions(thing.reg_offset, thing.size)
643
+ return self.get_register_definitions(thing.reg_offset, thing.size)
636
644
  elif isinstance(thing, MemoryLocation):
637
645
  if isinstance(thing.addr, SpOffset):
638
- yield from self.get_stack_definitions(thing.addr.offset, thing.size, thing.endness)
646
+ return self.get_stack_definitions(thing.addr.offset, thing.size)
639
647
  elif isinstance(thing.addr, HeapAddress):
640
- yield from self.get_heap_definitions(thing.addr.value, size=thing.size, endness=thing.endness)
648
+ return self.get_heap_definitions(thing.addr.value, size=thing.size)
641
649
  elif isinstance(thing.addr, int):
642
- yield from self.get_memory_definitions(thing.addr, thing.size, thing.endness)
650
+ return self.get_memory_definitions(thing.addr, thing.size)
643
651
  else:
644
- return
652
+ return set()
645
653
  elif isinstance(thing, Tmp):
646
- yield from self.get_tmp_definitions(thing.tmp_idx)
654
+ return self.get_tmp_definitions(thing.tmp_idx)
647
655
  else:
656
+ defs = set()
648
657
  for mvs in self.others.get(thing, {}).values():
649
658
  for mv in mvs:
650
- yield from self.get_definitions(mv)
659
+ defs |= self.get_definitions(mv)
660
+ return defs
651
661
 
652
- def get_tmp_definitions(self, tmp_idx: int) -> Iterable[Definition]:
662
+ def get_tmp_definitions(self, tmp_idx: int) -> Set[Definition]:
653
663
  if tmp_idx in self.tmps:
654
- yield from self.tmps[tmp_idx]
664
+ return self.tmps[tmp_idx]
655
665
  else:
656
- return
666
+ return set()
657
667
 
658
- def get_register_definitions(self, reg_offset: int, size: int, endness=None) -> Iterable[Definition]:
668
+ def get_register_definitions(self, reg_offset: int, size: int) -> Set[Definition]:
659
669
  try:
660
- values: MultiValues = self.registers.load(
661
- reg_offset,
662
- size=size,
663
- endness=endness,
664
- )
670
+ annotations = self.registers.load_annotations(reg_offset, size)
665
671
  except SimMemoryMissingError as ex:
666
- # load values and stop at the missing location
667
672
  if ex.missing_addr > reg_offset:
668
- values: MultiValues = self.registers.load(
669
- reg_offset, size=ex.missing_addr - reg_offset, endness=endness
670
- )
673
+ annotations = self.registers.load_annotations(reg_offset, ex.missing_addr - reg_offset)
671
674
  else:
672
675
  # nothing we can do
673
- return
674
- yield from LiveDefinitions.extract_defs_from_mv(values)
676
+ return set()
677
+
678
+ return LiveDefinitions.extract_defs_from_annotations(annotations)
675
679
 
676
680
  def get_stack_values(self, stack_offset: int, size: int, endness: str) -> Optional[MultiValues]:
677
681
  stack_addr = self.stack_offset_to_stack_addr(stack_offset)
@@ -680,31 +684,36 @@ class LiveDefinitions:
680
684
  except SimMemoryMissingError:
681
685
  return None
682
686
 
683
- def get_stack_definitions(self, stack_offset: int, size: int, endness) -> Iterable[Definition]:
684
- mv = self.get_stack_values(stack_offset, size, endness)
685
- if not mv:
686
- return
687
- yield from LiveDefinitions.extract_defs_from_mv(mv)
687
+ def get_stack_definitions(self, stack_offset: int, size: int) -> Set[Definition]:
688
+ try:
689
+ stack_addr = self.stack_offset_to_stack_addr(stack_offset)
690
+ annotations = self.stack.load_annotations(stack_addr, size)
691
+ except SimMemoryMissingError:
692
+ return set()
688
693
 
689
- def get_heap_definitions(self, heap_addr: int, size: int, endness) -> Iterable[Definition]:
694
+ return LiveDefinitions.extract_defs_from_annotations(annotations)
695
+
696
+ def get_heap_definitions(self, heap_addr: int, size: int) -> Set[Definition]:
690
697
  try:
691
- mv: MultiValues = self.heap.load(heap_addr, size=size, endness=endness)
698
+ annotations = self.heap.load_annotations(heap_addr, size)
692
699
  except SimMemoryMissingError:
693
- return
694
- yield from LiveDefinitions.extract_defs_from_mv(mv)
700
+ return set()
701
+
702
+ return LiveDefinitions.extract_defs_from_annotations(annotations)
695
703
 
696
- def get_memory_definitions(self, addr: int, size: int, endness) -> Iterable[Definition]:
704
+ def get_memory_definitions(self, addr: int, size: int) -> Set[Definition]:
697
705
  try:
698
- values = self.memory.load(addr, size=size, endness=endness)
706
+ annotations = self.memory.load_annotations(addr, size)
699
707
  except SimMemoryMissingError:
700
- return
701
- yield from LiveDefinitions.extract_defs_from_mv(values)
708
+ return set()
709
+
710
+ return LiveDefinitions.extract_defs_from_annotations(annotations)
702
711
 
703
712
  @deprecated("get_definitions")
704
713
  def get_definitions_from_atoms(self, atoms: Iterable[Atom]) -> Iterable[Definition]:
705
714
  result = set()
706
715
  for atom in atoms:
707
- result |= set(self.get_definitions(atom))
716
+ result |= self.get_definitions(atom)
708
717
  return result
709
718
 
710
719
  @deprecated("get_values")
@@ -905,7 +914,7 @@ class LiveDefinitions:
905
914
 
906
915
  def add_memory_use(self, atom: MemoryLocation, code_loc: CodeLocation, expr: Optional[Any] = None) -> None:
907
916
  # get all current definitions
908
- current_defs: Iterable[Definition] = self.get_definitions(atom)
917
+ current_defs: Set[Definition] = self.get_definitions(atom)
909
918
 
910
919
  for current_def in current_defs:
911
920
  self.add_memory_use_by_def(current_def, code_loc, expr=expr)
@@ -1,7 +1,9 @@
1
- from typing import DefaultDict, Optional, List, Set, Tuple, TYPE_CHECKING
1
+ from typing import DefaultDict, Optional, List, Set, Tuple, Dict, TYPE_CHECKING
2
2
 
3
3
  from collections import defaultdict
4
+ from itertools import chain
4
5
 
6
+ from angr.utils.constants import DEFAULT_STATEMENT
5
7
  from angr.knowledge_plugins.key_definitions.atoms import Tmp
6
8
 
7
9
  from .constants import ObservationPointType, OP_BEFORE, OP_AFTER
@@ -15,6 +17,7 @@ LocationType = Tuple[int, Optional[int], Optional[int]] # block addr, block ID,
15
17
  LocationWithPosType = Tuple[
16
18
  int, Optional[int], Optional[int], ObservationPointType
17
19
  ] # block addr, block ID, stmt ID, before/after
20
+ BlockAddrType = Tuple[int, Optional[int]] # block addr, block ID
18
21
 
19
22
 
20
23
  class Liveness:
@@ -25,30 +28,37 @@ class Liveness:
25
28
  def __init__(self):
26
29
  self.curr_live_defs: Set["Definition"] = set()
27
30
  self.curr_loc: Optional[LocationType] = None
28
- self.def_to_liveness: DefaultDict["Definition", Set[LocationType]] = defaultdict(set)
29
- self.loc_to_defs: DefaultDict[LocationWithPosType, Set["Definition"]] = defaultdict(set)
30
- self._node_max_stmt_id: DefaultDict[Tuple[int, Optional[int]], int] = defaultdict(int)
31
-
32
- def add_def(self, d: "Definition", code_loc: "CodeLocation") -> None:
33
- loc = (code_loc.block_addr, code_loc.block_idx, code_loc.stmt_idx)
31
+ self.curr_block: Optional[BlockAddrType] = None
32
+ self.curr_stmt_idx: Optional[int] = None
33
+ self.blockstart_to_defs: DefaultDict[BlockAddrType, Set["Definition"]] = defaultdict(set)
34
+ self.blockend_to_defs: DefaultDict[BlockAddrType, Set["Definition"]] = defaultdict(set)
35
+ self.loc_to_killed_defs: DefaultDict[BlockAddrType, Dict[int, Set["Definition"]]] = defaultdict(dict)
36
+ self.loc_to_added_defs: DefaultDict[BlockAddrType, Dict[int, Set["Definition"]]] = defaultdict(dict)
37
+ self._node_max_stmt_id: DefaultDict[BlockAddrType, int] = defaultdict(int)
38
+
39
+ def add_def(self, d: "Definition") -> None:
34
40
  self.curr_live_defs.add(d)
35
- self.def_to_liveness[d].add(loc)
41
+ if self.curr_stmt_idx not in self.loc_to_added_defs[self.curr_block]:
42
+ self.loc_to_added_defs[self.curr_block][self.curr_stmt_idx] = set()
43
+ self.loc_to_added_defs[self.curr_block][self.curr_stmt_idx].add(d)
36
44
 
37
45
  def kill_def(self, d: "Definition") -> None:
38
46
  self.curr_live_defs.discard(d)
47
+ if self.curr_stmt_idx not in self.loc_to_killed_defs[self.curr_block]:
48
+ self.loc_to_killed_defs[self.curr_block][self.curr_stmt_idx] = set()
49
+ self.loc_to_killed_defs[self.curr_block][self.curr_stmt_idx].add(d)
39
50
 
40
- def complete_loc(self) -> None:
41
- if self.curr_loc is not None:
42
- for live_def in self.curr_live_defs:
43
- self.def_to_liveness[live_def].add(self.curr_loc)
44
- self.loc_to_defs[self.curr_loc + (OP_AFTER,)] |= self.curr_live_defs
51
+ def make_liveness_snapshot(self) -> None:
52
+ if self.curr_block is not None:
53
+ self.blockend_to_defs[self.curr_block] |= self.curr_live_defs
45
54
 
46
55
  def at_new_stmt(self, code_loc: "CodeLocation") -> None:
47
56
  """
48
57
  Only support moving from a statement to the next statement within one basic block.
49
58
  """
50
- self.complete_loc()
51
59
  self.curr_loc = code_loc.block_addr, code_loc.block_idx, code_loc.stmt_idx
60
+ self.curr_block = code_loc.block_addr, code_loc.block_idx
61
+ self.curr_stmt_idx = code_loc.stmt_idx
52
62
  if (
53
63
  code_loc.stmt_idx is not None
54
64
  and code_loc.stmt_idx > self._node_max_stmt_id[(code_loc.block_addr, code_loc.block_idx)]
@@ -59,44 +69,102 @@ class Liveness:
59
69
  """
60
70
  Only support moving to a new block from one or more blocks.
61
71
  """
72
+ self.make_liveness_snapshot()
73
+
62
74
  loc = code_loc.block_addr, code_loc.block_idx, code_loc.stmt_idx
63
- key = code_loc.block_addr, code_loc.block_idx, code_loc.stmt_idx, OP_BEFORE
75
+ key = code_loc.block_addr, code_loc.block_idx
64
76
  for pred_codeloc in pred_codelocs:
65
- if pred_codeloc.stmt_idx is None:
66
- # external code location
67
- pred_max_stmt_id = None
68
- else:
69
- pred_max_stmt_id = self._node_max_stmt_id[(pred_codeloc.block_addr, pred_codeloc.block_idx)]
70
- pred_key = pred_codeloc.block_addr, pred_codeloc.block_idx, pred_max_stmt_id, OP_AFTER
71
- all_pred_defs = self.loc_to_defs[pred_key]
77
+ all_pred_defs = self.blockend_to_defs[pred_codeloc.block_addr, pred_codeloc.block_idx]
72
78
 
73
79
  # remove tmp defs
74
80
  pred_defs = set()
75
81
  for pred_def in all_pred_defs:
76
82
  if not isinstance(pred_def.atom, Tmp):
77
83
  pred_defs.add(pred_def)
78
- for pred_def in pred_defs:
79
- self.def_to_liveness[pred_def].add(loc)
80
- self.loc_to_defs[key] |= pred_defs
84
+ self.blockstart_to_defs[key] |= pred_defs
81
85
 
82
- self.curr_live_defs = set(self.loc_to_defs[key])
86
+ self.curr_live_defs = self.blockstart_to_defs[key].copy()
83
87
  self.curr_loc = loc
88
+ self.curr_stmt_idx = 0
84
89
 
85
90
  def find_defs_at(self, code_loc: "CodeLocation", op: int = OP_BEFORE) -> Set["Definition"]:
86
- if op == OP_BEFORE:
87
- if code_loc.stmt_idx != 0:
88
- loc = code_loc.block_addr, code_loc.block_idx, code_loc.stmt_idx - 1, OP_AFTER
91
+ return self.find_defs_at_raw(code_loc.block_addr, code_loc.block_idx, code_loc.stmt_idx, op=op)
92
+
93
+ def find_defs_at_raw(
94
+ self, block_addr: int, block_idx: Optional[int], stmt_idx: Optional[int], op: int = OP_BEFORE
95
+ ) -> Set["Definition"]:
96
+ block: BlockAddrType = block_addr, block_idx
97
+ if block not in self.blockstart_to_defs:
98
+ defs = set()
99
+ else:
100
+ defs = self.blockstart_to_defs[block].copy()
101
+
102
+ if stmt_idx is None:
103
+ return defs
104
+
105
+ added_defs = self.loc_to_added_defs[block] if block in self.loc_to_added_defs else None
106
+ killed_defs = self.loc_to_killed_defs[block] if block in self.loc_to_added_defs else None
107
+
108
+ if stmt_idx == DEFAULT_STATEMENT:
109
+ end_stmt_idx = self._node_max_stmt_id[block] + 1
110
+ else:
111
+ if op == OP_BEFORE:
112
+ end_stmt_idx = stmt_idx
89
113
  else:
90
- loc = code_loc.block_addr, code_loc.block_idx, 0, OP_BEFORE
114
+ end_stmt_idx = stmt_idx + 1
115
+
116
+ if added_defs is not None and killed_defs is not None:
117
+ indices = chain(added_defs, killed_defs)
118
+ elif added_defs is None and killed_defs is not None:
119
+ indices = killed_defs
120
+ elif added_defs is not None and killed_defs is None:
121
+ indices = added_defs
91
122
  else:
92
- loc = code_loc.block_addr, code_loc.block_idx, code_loc.stmt_idx, OP_AFTER
93
- return set() if loc not in self.loc_to_defs else self.loc_to_defs[loc]
123
+ indices = []
124
+
125
+ tmp_indices = []
126
+ if killed_defs is not None and None in killed_defs:
127
+ # External codeloc
128
+ defs.difference_update(killed_defs[None])
129
+ for idx in indices:
130
+ if idx is not None:
131
+ tmp_indices.append(idx)
132
+ indices = tmp_indices
133
+
134
+ tmp_indices = []
135
+ if added_defs is not None and None in added_defs:
136
+ # External codeloc
137
+ defs.update(added_defs[None])
138
+ for idx in indices:
139
+ if idx is not None:
140
+ tmp_indices.append(idx)
141
+ indices = tmp_indices
142
+
143
+ for idx in sorted(indices):
144
+ if idx >= end_stmt_idx:
145
+ break
146
+ if killed_defs is not None and idx in killed_defs:
147
+ defs.difference_update(killed_defs[idx])
148
+ if added_defs is not None and idx in added_defs:
149
+ defs.update(added_defs[idx])
150
+
151
+ if stmt_idx == DEFAULT_STATEMENT and op == OP_AFTER:
152
+ if killed_defs is not None and DEFAULT_STATEMENT in killed_defs:
153
+ defs.difference_update(killed_defs[DEFAULT_STATEMENT])
154
+ if added_defs is not None and DEFAULT_STATEMENT in added_defs:
155
+ defs.update(added_defs[DEFAULT_STATEMENT])
156
+
157
+ return defs
94
158
 
95
159
  def copy(self) -> "Liveness":
96
160
  o = Liveness()
97
161
  o.curr_live_defs = self.curr_live_defs.copy()
98
162
  o.curr_loc = self.curr_loc
99
- o.def_to_liveness = self.def_to_liveness.copy()
100
- o.loc_to_defs = self.loc_to_defs.copy()
163
+ o.curr_block = self.curr_block
164
+ o.curr_stmt_idx = self.curr_stmt_idx
165
+ o.blockstart_to_defs = self.blockstart_to_defs.copy()
166
+ o.blockend_to_defs = self.blockend_to_defs.copy()
167
+ o.loc_to_added_defs = self.loc_to_added_defs.copy()
168
+ o.loc_to_killed_defs = self.loc_to_killed_defs.copy()
101
169
  o._node_max_stmt_id = self._node_max_stmt_id.copy()
102
170
  return o
@@ -32,9 +32,9 @@ class ReachingDefinitionsModel:
32
32
  len(self.observed_results),
33
33
  )
34
34
 
35
- def add_def(self, d: "Definition", codeloc: "CodeLocation") -> None:
35
+ def add_def(self, d: "Definition") -> None:
36
36
  if self.liveness is not None:
37
- self.liveness.add_def(d, codeloc)
37
+ self.liveness.add_def(d)
38
38
 
39
39
  def kill_def(self, d: "Definition") -> None:
40
40
  if self.liveness is not None:
@@ -48,9 +48,9 @@ class ReachingDefinitionsModel:
48
48
  if self.liveness is not None:
49
49
  self.liveness.at_new_block(code_loc, pred_codelocs)
50
50
 
51
- def complete_loc(self) -> None:
51
+ def make_liveness_snapshot(self) -> None:
52
52
  if self.liveness is not None:
53
- self.liveness.complete_loc()
53
+ self.liveness.make_liveness_snapshot()
54
54
 
55
55
  def find_defs_at(self, code_loc: "CodeLocation", op: int = OP_BEFORE) -> Set["Definition"]:
56
56
  return self.liveness.find_defs_at(code_loc, op=op)
@@ -808,7 +808,9 @@ class PropagatorAILState(PropagatorState):
808
808
  or isinstance(old, ailment.Expr.Register)
809
809
  and (old.reg_offset == self.arch.sp_offset or (not bp_as_gpr and old.reg_offset == self.arch.bp_offset))
810
810
  ):
811
- self._replacements[codeloc][old] = new
811
+ self._replacements[codeloc][old] = (
812
+ new if stmt_to_remove is None else {"expr": new, "stmt_to_remove": stmt_to_remove}
813
+ )
812
814
  replaced = True
813
815
  else:
814
816
  prop_count = 0
@@ -90,6 +90,7 @@ class VariableManagerInternal(Serializable):
90
90
  self._atom_to_variable: Dict[
91
91
  Union[Tuple[int, int], Tuple[int, int, int]], Dict[int, Set[Tuple[SimVariable, int]]]
92
92
  ] = defaultdict(_defaultdict_set)
93
+ self._ident_to_variable: Dict[str, SimVariable] = {}
93
94
  self._variable_counters = {
94
95
  "register": count(),
95
96
  "stack": count(),
@@ -109,6 +110,9 @@ class VariableManagerInternal(Serializable):
109
110
  self.variable_to_types: Dict[SimVariable, SimType] = {}
110
111
  self.variables_with_manual_types = set()
111
112
 
113
+ # optimization
114
+ self._variables_without_writes = set()
115
+
112
116
  self.ret_val_size = None
113
117
 
114
118
  #
@@ -241,6 +245,7 @@ class VariableManagerInternal(Serializable):
241
245
  model._phi_variables[var] = set()
242
246
  else:
243
247
  model._variables.add(var)
248
+ model._ident_to_variable[var.ident] = var
244
249
 
245
250
  # variable accesses
246
251
  for varaccess_pb2 in cmsg.accesses:
@@ -314,6 +319,8 @@ class VariableManagerInternal(Serializable):
314
319
 
315
320
  region.add_variable(offset, var)
316
321
 
322
+ model._variables_without_writes = model.get_variables_without_writes()
323
+
317
324
  return model
318
325
 
319
326
  #
@@ -338,7 +345,7 @@ class VariableManagerInternal(Serializable):
338
345
  ident = "i%s_%d" % (prefix, next(self._variable_counters[sort]))
339
346
  return ident
340
347
 
341
- def add_variable(self, sort, start, variable):
348
+ def add_variable(self, sort, start, variable: SimVariable):
342
349
  if sort == "stack":
343
350
  region = self._stack_region
344
351
  elif sort == "register":
@@ -347,17 +354,17 @@ class VariableManagerInternal(Serializable):
347
354
  region = self._global_region
348
355
  else:
349
356
  raise ValueError("Unsupported sort %s in add_variable()." % sort)
350
- existing = [x for x in region.get_variables_by_offset(start) if x.ident == variable.ident]
351
- if len(existing) == 1:
352
- var = existing[0]
353
- if var.name is not None and not variable.renamed:
354
- variable.name = var.name
355
- variable.renamed = var.renamed
356
- else:
357
- # implicitly overwrite or add I guess
358
- pass
357
+
358
+ # find if there is already an existing variable with the same identifier
359
+ if variable.ident in self._ident_to_variable:
360
+ existing_var = self._ident_to_variable[variable.ident]
361
+ if existing_var.name is not None and not variable.renamed:
362
+ variable.name = existing_var.name
363
+ variable.renamed = existing_var.renamed
364
+ self._ident_to_variable[variable.ident] = variable
359
365
  region.add_variable(start, variable)
360
366
  self._variables.add(variable)
367
+ self._variables_without_writes.add(variable)
361
368
 
362
369
  def set_variable(self, sort, start, variable: SimVariable):
363
370
  if sort == "stack":
@@ -368,17 +375,15 @@ class VariableManagerInternal(Serializable):
368
375
  region = self._global_region
369
376
  else:
370
377
  raise ValueError("Unsupported sort %s in set_variable()." % sort)
371
- existing = [x for x in region.get_variables_by_offset(start) if x.ident == variable.ident]
372
- if len(existing) == 1:
373
- var = existing[0]
374
- if var.name is not None and not variable.renamed:
375
- variable.name = var.name
376
- variable.renamed = var.renamed
377
- else:
378
- # implicitly overwrite or add I guess
379
- pass
378
+ # find if there is already an existing variable with the same identifier
379
+ if variable.ident in self._ident_to_variable:
380
+ existing_var = self._ident_to_variable[variable.ident]
381
+ if existing_var.name is not None and not variable.renamed:
382
+ variable.name = existing_var.name
383
+ variable.renamed = existing_var.renamed
380
384
  region.set_variable(start, variable)
381
385
  self._variables.add(variable)
386
+ self._variables_without_writes.add(variable)
382
387
 
383
388
  def write_to(self, variable, offset, location, overwrite=False, atom=None):
384
389
  self._record_variable_access(
@@ -404,17 +409,19 @@ class VariableManagerInternal(Serializable):
404
409
  overwrite=False,
405
410
  atom=None,
406
411
  ):
407
- # TODO can this line be removed, should we be only adding to _variables in add_variable?
408
- self._variables.add(variable)
409
412
  atom_hash = (hash(atom) & 0xFFFF_FFFF) if atom is not None else None
410
413
  if overwrite:
411
414
  self._variable_accesses[variable] = {VariableAccess(variable, sort, location, offset, atom_hash=atom_hash)}
412
415
  else:
413
416
  self._variable_accesses[variable].add(VariableAccess(variable, sort, location, offset, atom_hash=atom_hash))
414
417
  self.record_variable(location, variable, offset, overwrite=overwrite, atom=atom)
418
+ if sort == VariableAccessSort.WRITE and variable in self._variables_without_writes:
419
+ self._variables_without_writes.discard(variable)
415
420
 
416
421
  def record_variable(self, location: "CodeLocation", variable, offset, overwrite=False, atom=None):
417
- self._variables.add(variable)
422
+ if variable.ident not in self._ident_to_variable:
423
+ self._ident_to_variable[variable.ident] = variable
424
+ self._variables.add(variable)
418
425
  var_and_offset = variable, offset
419
426
  atom_hash = (hash(atom) & 0xFFFF_FFFF) if atom is not None else None
420
427
  key = (
@@ -693,7 +700,7 @@ class VariableManagerInternal(Serializable):
693
700
  variables[phi] = self._phi_variables[phi]
694
701
  return variables
695
702
 
696
- def input_variables(self, exclude_specials=True):
703
+ def get_variables_without_writes(self) -> List[SimVariable]:
697
704
  """
698
705
  Get all variables that have never been written to.
699
706
 
@@ -703,16 +710,35 @@ class VariableManagerInternal(Serializable):
703
710
  def has_write_access(accesses):
704
711
  return any(acc for acc in accesses if acc.access_type == VariableAccessSort.WRITE)
705
712
 
713
+ input_variables = []
714
+
715
+ for variable, accesses in self._variable_accesses.items():
716
+ if variable in self._phi_variables:
717
+ # a phi variable is definitely not an input variable
718
+ continue
719
+ if not has_write_access(accesses):
720
+ input_variables.append(variable)
721
+
722
+ return input_variables
723
+
724
+ def input_variables(self, exclude_specials: bool = True):
725
+ """
726
+ Get all variables that have never been written to.
727
+
728
+ :return: A list of variables that are never written to.
729
+ """
730
+
706
731
  def has_read_access(accesses):
707
732
  return any(acc for acc in accesses if acc.access_type == VariableAccessSort.READ)
708
733
 
709
734
  input_variables = []
710
735
 
711
- for variable, accesses in self._variable_accesses.items():
736
+ for variable in self._variables_without_writes:
712
737
  if variable in self._phi_variables:
713
738
  # a phi variable is definitely not an input variable
714
739
  continue
715
- if not has_write_access(accesses) and has_read_access(accesses):
740
+ accesses = self._variable_accesses[variable]
741
+ if has_read_access(accesses):
716
742
  if not exclude_specials or not variable.category:
717
743
  input_variables.append(variable)
718
744
 
angr/lib/angr_native.dll CHANGED
Binary file
angr/misc/bug_report.py CHANGED
@@ -1,4 +1,4 @@
1
- import imp
1
+ import importlib
2
2
  import os
3
3
  import sys
4
4
  import datetime
@@ -41,7 +41,7 @@ def print_versions():
41
41
  for m in angr_modules:
42
42
  print("######## %s #########" % m)
43
43
  try:
44
- _, python_filename, _ = imp.find_module(m)
44
+ python_filename = importlib.util.find_spec(m).origin
45
45
  except ImportError:
46
46
  print("Python could not find " + m)
47
47
  continue
@@ -1,4 +1,4 @@
1
- # pylint:disable=abstract-method
1
+ # pylint:disable=abstract-method,wrong-import-position,unused-argument,missing-class-docstring,arguments-differ
2
2
  from typing import Iterable, Tuple, Dict, Any, Optional
3
3
 
4
4
  import claripy
@@ -114,7 +114,6 @@ class MemoryMixin(SimStatePlugin):
114
114
 
115
115
  The ``inspect``, ``events``, and ``key`` parameters are for ``state.solver.Unconstrained``, if it is used.
116
116
  """
117
- pass
118
117
 
119
118
  def _merge_values(self, values: Iterable[Tuple[Any, Any]], merged_size: int, **kwargs) -> Optional[Any]:
120
119
  """
@@ -187,6 +186,7 @@ from .paged_memory.paged_memory_mixin import (
187
186
  )
188
187
  from .paged_memory.privileged_mixin import PrivilegedPagingMixin
189
188
  from .paged_memory.stack_allocation_mixin import StackAllocationMixin
189
+ from .paged_memory.paged_memory_multivalue_mixin import PagedMemoryMultiValueMixin
190
190
  from .paged_memory.pages import *
191
191
 
192
192
  from .slotted_memory import SlottedMemoryMixin
@@ -353,6 +353,7 @@ class MultiValuedMemory(
353
353
  DefaultFillerMixin,
354
354
  MultiValueMergerMixin,
355
355
  PagedMemoryMixin,
356
+ PagedMemoryMultiValueMixin,
356
357
  ):
357
358
  def _default_value(self, addr, size, **kwargs):
358
359
  # TODO: Make _default_value() a separate Mixin
@@ -0,0 +1,63 @@
1
+ from .. import MemoryMixin
2
+
3
+
4
+ class PagedMemoryMultiValueMixin(MemoryMixin):
5
+ """
6
+ Implement optimizations and fast accessors for the MultiValues-variant of Paged Memory.
7
+ """
8
+
9
+ def load_annotations(self, addr: int, size: int, **kwargs):
10
+ if not isinstance(size, int):
11
+ raise TypeError("Need size to be resolved to an int by this point")
12
+
13
+ if not isinstance(addr, int):
14
+ raise TypeError("Need addr to be resolved to an int by this point")
15
+
16
+ pageno, pageoff = self._divide_addr(addr)
17
+
18
+ annotations = set()
19
+
20
+ # fasttrack basic case
21
+ if pageoff + size <= self.page_size:
22
+ page = self._get_page(pageno, False, **kwargs)
23
+ loaded = page.load(
24
+ pageoff,
25
+ size=size,
26
+ page_addr=pageno * self.page_size,
27
+ memory=self,
28
+ cooperate=True,
29
+ **kwargs,
30
+ )
31
+ for _, mos in loaded:
32
+ if isinstance(mos, set):
33
+ for mo in mos:
34
+ annotations.update(mo.object.annotations)
35
+ else:
36
+ annotations.update(mos.object.annotations)
37
+
38
+ else:
39
+ max_pageno = (1 << self.state.arch.bits) // self.page_size
40
+ bytes_done = 0
41
+ while bytes_done < size:
42
+ page = self._get_page(pageno, False, **kwargs)
43
+ sub_size = min(self.page_size - pageoff, size - bytes_done)
44
+ loaded = page.load(
45
+ pageoff,
46
+ size=sub_size,
47
+ page_addr=pageno * self.page_size,
48
+ memory=self,
49
+ cooperate=True,
50
+ **kwargs,
51
+ )
52
+ for _, mos in loaded:
53
+ if isinstance(mos, set):
54
+ for mo in mos:
55
+ annotations.update(mo.object.annotations)
56
+ else:
57
+ annotations.update(mos.object.annotations)
58
+
59
+ bytes_done += sub_size
60
+ pageno = (pageno + 1) % max_pageno
61
+ pageoff = 0
62
+
63
+ return annotations