angr 9.2.152__py3-none-macosx_11_0_arm64.whl → 9.2.154__py3-none-macosx_11_0_arm64.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 (32) hide show
  1. angr/__init__.py +1 -1
  2. angr/analyses/analysis.py +3 -3
  3. angr/analyses/calling_convention/fact_collector.py +8 -14
  4. angr/analyses/cfg/cfg_base.py +1 -1
  5. angr/analyses/cfg/cfg_fast.py +40 -1
  6. angr/analyses/decompiler/ail_simplifier.py +0 -1
  7. angr/analyses/decompiler/callsite_maker.py +17 -17
  8. angr/analyses/decompiler/ccall_rewriters/x86_ccalls.py +210 -1
  9. angr/analyses/decompiler/clinic.py +51 -13
  10. angr/analyses/decompiler/decompilation_cache.py +1 -1
  11. angr/analyses/decompiler/region_identifier.py +171 -119
  12. angr/analyses/decompiler/ssailification/ssailification.py +1 -1
  13. angr/analyses/decompiler/structured_codegen/c.py +15 -15
  14. angr/analyses/decompiler/structuring/phoenix.py +28 -0
  15. angr/analyses/decompiler/structuring/structurer_nodes.py +11 -0
  16. angr/analyses/reaching_definitions/function_handler.py +13 -19
  17. angr/analyses/smc.py +3 -1
  18. angr/analyses/stack_pointer_tracker.py +7 -1
  19. angr/analyses/typehoon/simple_solver.py +143 -81
  20. angr/analyses/typehoon/typehoon.py +2 -1
  21. angr/analyses/variable_recovery/engine_ail.py +14 -25
  22. angr/analyses/variable_recovery/engine_base.py +1 -1
  23. angr/knowledge_plugins/functions/function.py +10 -4
  24. angr/lib/angr_native.dylib +0 -0
  25. angr/sim_type.py +11 -70
  26. angr/utils/types.py +93 -1
  27. {angr-9.2.152.dist-info → angr-9.2.154.dist-info}/METADATA +6 -6
  28. {angr-9.2.152.dist-info → angr-9.2.154.dist-info}/RECORD +32 -32
  29. {angr-9.2.152.dist-info → angr-9.2.154.dist-info}/WHEEL +1 -1
  30. {angr-9.2.152.dist-info → angr-9.2.154.dist-info}/entry_points.txt +0 -0
  31. {angr-9.2.152.dist-info → angr-9.2.154.dist-info}/licenses/LICENSE +0 -0
  32. {angr-9.2.152.dist-info → angr-9.2.154.dist-info}/top_level.txt +0 -0
@@ -17,6 +17,7 @@ from angr.knowledge_plugins import Function
17
17
  from angr.block import BlockNode
18
18
  from angr.errors import SimTranslationError
19
19
  from angr.calling_conventions import SimStackArg
20
+ from angr.utils.types import dereference_simtype_by_lib
20
21
 
21
22
  from .analysis import Analysis
22
23
 
@@ -812,10 +813,15 @@ class StackPointerTracker(Analysis, ForwardAnalysis):
812
813
  if v is BOTTOM:
813
814
  incremented = BOTTOM
814
815
  elif callee.prototype is not None:
816
+ proto = (
817
+ dereference_simtype_by_lib(callee.prototype, callee.prototype_libname)
818
+ if callee.prototype_libname
819
+ else callee.prototype
820
+ )
815
821
  num_stack_args = len(
816
822
  [
817
823
  arg_loc
818
- for arg_loc in callee.calling_convention.arg_locs(callee.prototype)
824
+ for arg_loc in callee.calling_convention.arg_locs(proto)
819
825
  if isinstance(arg_loc, SimStackArg)
820
826
  ]
821
827
  )
@@ -2,6 +2,7 @@
2
2
  from __future__ import annotations
3
3
  import enum
4
4
  from collections import defaultdict
5
+ from contextlib import suppress
5
6
  import logging
6
7
 
7
8
  import networkx
@@ -51,23 +52,6 @@ from .dfa import DFAConstraintSolver, EmptyEpsilonNFAError
51
52
  _l = logging.getLogger(__name__)
52
53
 
53
54
 
54
- PRIMITIVE_TYPES = {
55
- TopType(),
56
- Int(),
57
- Int8(),
58
- Int16(),
59
- Int32(),
60
- Int64(),
61
- Pointer32(),
62
- Pointer64(),
63
- BottomType(),
64
- Struct(),
65
- Array(),
66
- Float(),
67
- Float32(),
68
- Float64(),
69
- }
70
-
71
55
  Top_ = TopType()
72
56
  Int_ = Int()
73
57
  Int64_ = Int64()
@@ -83,6 +67,25 @@ Float_ = Float()
83
67
  Float32_ = Float32()
84
68
  Float64_ = Float64()
85
69
 
70
+
71
+ PRIMITIVE_TYPES = {
72
+ Top_,
73
+ Int_,
74
+ Int8_,
75
+ Int16_,
76
+ Int32_,
77
+ Int64_,
78
+ Pointer32_,
79
+ Pointer64_,
80
+ Bottom_,
81
+ Struct_,
82
+ Array_,
83
+ Float_,
84
+ Float32_,
85
+ Float64_,
86
+ }
87
+
88
+
86
89
  # lattice for 64-bit binaries
87
90
  BASE_LATTICE_64 = networkx.DiGraph()
88
91
  BASE_LATTICE_64.add_edge(Top_, Int_)
@@ -149,6 +152,24 @@ class SketchNode(SketchNodeBase):
149
152
  def __hash__(self):
150
153
  return hash((SketchNode, self.typevar))
151
154
 
155
+ @property
156
+ def size(self) -> int | None:
157
+ """
158
+ Best-effort estimation of the size of the typevar (in bits). Returns None if we cannot determine.
159
+ """
160
+
161
+ if isinstance(self.typevar, DerivedTypeVariable):
162
+ last_label = self.typevar.labels[-1]
163
+ if isinstance(last_label, HasField) and last_label.bits != MAX_POINTSTO_BITS:
164
+ return last_label.bits
165
+ if isinstance(self.lower_bound, TypeConstant) and not isinstance(self.lower_bound, (TopType, BottomType)):
166
+ with suppress(NotImplementedError):
167
+ return self.lower_bound.size * 8
168
+ if isinstance(self.upper_bound, TypeConstant) and not isinstance(self.upper_bound, (TopType, BottomType)):
169
+ with suppress(NotImplementedError):
170
+ return self.upper_bound.size * 8
171
+ return None
172
+
152
173
 
153
174
  class RecursiveRefNode(SketchNodeBase):
154
175
  """
@@ -433,9 +454,8 @@ class SimpleSolver:
433
454
  if isinstance(tv, TypeVariable) and isinstance(sol, TypeConstant):
434
455
  self.solution[tv] = sol
435
456
 
436
- equ_classes, sketches, _ = self.solve()
437
457
  self._solution_cache = {}
438
- self.determine(equ_classes, sketches, self.solution)
458
+ self.solve()
439
459
  for typevar in list(self._constraints):
440
460
  self._convert_arrays(self._constraints[typevar])
441
461
 
@@ -448,6 +468,11 @@ class SimpleSolver:
448
468
  - Build the constraint graph
449
469
  - Collect all constraints
450
470
  - Apply constraints to derive the lower and upper bounds
471
+ - Determine a solution for type variables with constraints
472
+ - Rewrite the constraint graph by replacing determined type variables with their solutions
473
+ - Solve repeatedly until all interesting type variables have solutions
474
+
475
+ By repeatedly solving until exhausting interesting type variables, we ensure the S-Trans rule is applied.
451
476
  """
452
477
 
453
478
  prem_typevars = set(self._constraints) | self._typevars
@@ -476,11 +501,7 @@ class SimpleSolver:
476
501
  elif isinstance(t, TypeVariable) and t in typevars:
477
502
  constrained_typevars.add(t)
478
503
 
479
- equivalence_classes, sketches = self.infer_shapes(typevars, constraints)
480
- # TODO: Handle global variables
481
-
482
- type_schemes = constraints
483
-
504
+ _, sketches = self.infer_shapes(typevars, constraints)
484
505
  constraintset2tvs = defaultdict(set)
485
506
  for idx, tv in enumerate(constrained_typevars):
486
507
  _l.debug("Collecting constraints for type variable %r (%d/%d)", tv, idx + 1, len(constrained_typevars))
@@ -490,20 +511,43 @@ class SimpleSolver:
490
511
 
491
512
  for idx, (constraint_subset, tvs) in enumerate(constraintset2tvs.items()):
492
513
  _l.debug(
493
- "Solving %d constraints for type variables %r (%d/%d)",
514
+ "Solving %d constraints for %d type variables %r (%d/%d)",
494
515
  len(constraint_subset),
516
+ len(tvs),
495
517
  tvs,
496
518
  idx + 1,
497
519
  len(constraintset2tvs),
498
520
  )
499
- base_constraint_graph = self._generate_constraint_graph(constraint_subset, tvs | PRIMITIVE_TYPES)
500
- for idx_0, tv in enumerate(tvs):
501
- _l.debug("Solving for type variable %r (%d/%d)", tv, idx_0 + 1, len(tvs))
502
- primitive_constraints = self._generate_primitive_constraints({tv}, base_constraint_graph)
521
+
522
+ while True:
523
+ base_constraint_graph = self._generate_constraint_graph(constraint_subset, tvs | PRIMITIVE_TYPES)
524
+ primitive_constraints = self._generate_primitive_constraints(tvs, base_constraint_graph)
525
+ tvs_with_primitive_constraints = set()
503
526
  for primitive_constraint in primitive_constraints:
527
+ tv = self._typevar_from_primitive_constraint(primitive_constraint)
528
+ tvs_with_primitive_constraints.add(tv)
529
+ assert tv is not None, f"Cannot find type variable in primitive constraint {primitive_constraint}"
504
530
  sketches[tv].add_constraint(primitive_constraint)
505
-
506
- return equivalence_classes, sketches, type_schemes
531
+ solutions = {}
532
+ self.determine(sketches, tvs_with_primitive_constraints, solutions)
533
+ _l.debug("Determined solutions for %d type variable(s).", len(tvs_with_primitive_constraints))
534
+ if not solutions:
535
+ break
536
+
537
+ self.solution |= solutions
538
+
539
+ tvs = {tv for tv in tvs if tv not in tvs_with_primitive_constraints}
540
+ if not tvs:
541
+ break
542
+ # rewrite existing constraints
543
+ new_constraint_subset = set()
544
+ for constraint in constraint_subset:
545
+ rewritten = self._rewrite_constraint(constraint, solutions)
546
+ new_constraint_subset.add(rewritten)
547
+ constraint_subset = new_constraint_subset
548
+
549
+ # set the solution for missing type vars to TOP
550
+ self.determine(sketches, set(sketches).difference(set(self.solution)), self.solution)
507
551
 
508
552
  def infer_shapes(
509
553
  self, typevars: set[TypeVariable], constraints: set[TypeConstraint]
@@ -593,7 +637,6 @@ class SimpleSolver:
593
637
  non_primitive_endpoints: set[TypeVariable | DerivedTypeVariable],
594
638
  constraint_graph,
595
639
  ) -> set[TypeConstraint]:
596
- # FIXME: Extract interesting variables
597
640
  constraints_0 = self._solve_constraints_between(constraint_graph, non_primitive_endpoints, PRIMITIVE_TYPES)
598
641
  constraints_1 = self._solve_constraints_between(constraint_graph, PRIMITIVE_TYPES, non_primitive_endpoints)
599
642
  return constraints_0 | constraints_1
@@ -612,6 +655,25 @@ class SimpleSolver:
612
655
  # TODO: Other types of constraints?
613
656
  return typevars
614
657
 
658
+ @staticmethod
659
+ def _typevar_from_primitive_constraint(constraint: TypeConstraint) -> TypeVariable | None:
660
+ if isinstance(constraint, Subtype):
661
+ if (
662
+ isinstance(constraint.sub_type, DerivedTypeVariable)
663
+ and type(constraint.sub_type.type_var) is TypeVariable
664
+ ):
665
+ return constraint.sub_type.type_var
666
+ if type(constraint.sub_type) is TypeVariable:
667
+ return constraint.sub_type
668
+ if (
669
+ isinstance(constraint.super_type, DerivedTypeVariable)
670
+ and type(constraint.super_type.type_var) is TypeVariable
671
+ ):
672
+ return constraint.super_type.type_var
673
+ if type(constraint.super_type) is TypeVariable:
674
+ return constraint.super_type
675
+ return None
676
+
615
677
  @staticmethod
616
678
  def _get_all_paths(
617
679
  graph: networkx.DiGraph,
@@ -825,7 +887,6 @@ class SimpleSolver:
825
887
  """
826
888
 
827
889
  graph = networkx.DiGraph()
828
- constraints = self._get_transitive_subtype_constraints(constraints)
829
890
  for constraint in constraints:
830
891
  if isinstance(constraint, Subtype):
831
892
  self._constraint_graph_add_edges(
@@ -836,33 +897,6 @@ class SimpleSolver:
836
897
  self._constraint_graph_recall_forget_split(graph)
837
898
  return graph
838
899
 
839
- @staticmethod
840
- def _get_transitive_subtype_constraints(constraints: set[TypeConstraint]) -> set[TypeConstraint]:
841
- """
842
- Apply the S-Trans rule: a <: b, b <: c => a <: c
843
- """
844
- tv2supertypes = defaultdict(set)
845
- for constraint in constraints:
846
- if isinstance(constraint, Subtype):
847
- tv2supertypes[constraint.sub_type].add(constraint.super_type)
848
-
849
- new_constraints = set()
850
- while True:
851
- changed = False
852
- for subtype, supertypes in tv2supertypes.items():
853
- supertypes_copy = set(supertypes)
854
- for supertype in supertypes_copy:
855
- if supertype in tv2supertypes:
856
- for supertype_ in tv2supertypes[supertype]:
857
- if supertype_ not in supertypes_copy:
858
- changed = True
859
- supertypes.add(supertype_)
860
- new_constraints.add(Subtype(subtype, supertype_))
861
- if not changed:
862
- break
863
-
864
- return constraints | new_constraints
865
-
866
900
  @staticmethod
867
901
  def _constraint_graph_add_recall_edges(graph: networkx.DiGraph, node: ConstraintGraphNode) -> None:
868
902
  while True:
@@ -1004,12 +1038,7 @@ class SimpleSolver:
1004
1038
  if typevar in typevar_set:
1005
1039
  return True
1006
1040
  if isinstance(typevar, Struct) and Struct_ in typevar_set:
1007
- if not typevar.fields:
1008
- return True
1009
- return all(
1010
- SimpleSolver._typevar_inside_set(field_typevar, typevar_set)
1011
- for field_typevar in typevar.fields.values()
1012
- )
1041
+ return True
1013
1042
  if isinstance(typevar, Array) and Array_ in typevar_set:
1014
1043
  return SimpleSolver._typevar_inside_set(typevar.element, typevar_set)
1015
1044
  if isinstance(typevar, Pointer) and (Pointer32_ in typevar_set or Pointer64_ in typevar_set):
@@ -1110,31 +1139,47 @@ class SimpleSolver:
1110
1139
  return Pointer64()
1111
1140
  return t
1112
1141
 
1142
+ @staticmethod
1143
+ def _rewrite_constraint(constraint: TypeConstraint, solutions: dict) -> TypeConstraint:
1144
+ if isinstance(constraint, Subtype):
1145
+ replaced = False
1146
+ if isinstance(constraint.sub_type, TypeVariable) and constraint.sub_type in solutions:
1147
+ sub_type = solutions[constraint.sub_type]
1148
+ replaced = True
1149
+ else:
1150
+ sub_type = constraint.sub_type
1151
+ if isinstance(constraint.super_type, TypeVariable) and constraint.super_type in solutions:
1152
+ super_type = solutions[constraint.super_type]
1153
+ replaced = True
1154
+ else:
1155
+ super_type = constraint.super_type
1156
+ return Subtype(sub_type, super_type) if replaced else constraint
1157
+ return constraint
1158
+
1113
1159
  def determine(
1114
1160
  self,
1115
- equivalent_classes: dict[TypeVariable, TypeVariable],
1116
1161
  sketches,
1162
+ tvs,
1117
1163
  solution: dict,
1118
1164
  nodes: set[SketchNode] | None = None,
1119
1165
  ) -> None:
1120
1166
  """
1121
1167
  Determine C-like types from sketches.
1122
1168
 
1123
- :param equivalent_classes: A dictionary mapping each type variable from its representative in the equivalence
1124
- class over ~.
1125
1169
  :param sketches: A dictionary storing sketches for each type variable.
1126
1170
  :param solution: The dictionary storing C-like types for each type variable. Output.
1127
1171
  :param nodes: Optional. Nodes that should be considered in the sketch.
1128
1172
  :return: None
1129
1173
  """
1130
- for typevar, sketch in sketches.items():
1131
- self._determine(equivalent_classes, typevar, sketch, solution, nodes=nodes)
1132
1174
 
1133
- for v, e in self._equivalence.items():
1134
- if v not in solution and e in solution:
1135
- solution[v] = solution[e]
1175
+ for typevar in tvs:
1176
+ self._determine(typevar, sketches[typevar], solution, nodes=nodes)
1177
+
1178
+ for v, eq in self._equivalence.items():
1179
+ if v not in solution and eq in solution:
1180
+ solution[v] = solution[eq]
1136
1181
 
1137
- def _determine(self, equivalent_classes, the_typevar, sketch, solution: dict, nodes: set[SketchNode] | None = None):
1182
+ def _determine(self, the_typevar, sketch, solution: dict, nodes: set[SketchNode] | None = None):
1138
1183
  """
1139
1184
  Return the solution from sketches
1140
1185
  """
@@ -1194,7 +1239,7 @@ class SimpleSolver:
1194
1239
  for vals, out in [(func_inputs, input_args), (func_outputs, output_values)]:
1195
1240
  for idx in range(max(vals) + 1):
1196
1241
  if idx in vals:
1197
- sol = self._determine(equivalent_classes, the_typevar, sketch, solution, nodes=vals[idx])
1242
+ sol = self._determine(the_typevar, sketch, solution, nodes=vals[idx])
1198
1243
  out.append(sol)
1199
1244
  else:
1200
1245
  out.append(None)
@@ -1290,7 +1335,7 @@ class SimpleSolver:
1290
1335
  offset = sorted_offsets[i]
1291
1336
 
1292
1337
  child_nodes = node_by_offset[offset]
1293
- sol = self._determine(equivalent_classes, the_typevar, sketch, solution, nodes=child_nodes)
1338
+ sol = self._determine(the_typevar, sketch, solution, nodes=child_nodes)
1294
1339
  if isinstance(sol, TopType):
1295
1340
  # make it an array if possible
1296
1341
  elem_size = min(offset_to_sizes[offset])
@@ -1323,12 +1368,20 @@ class SimpleSolver:
1323
1368
  lower_bound = Bottom_
1324
1369
  upper_bound = Top_
1325
1370
 
1371
+ node_sizes = set()
1326
1372
  for node in nodes:
1327
- lower_bound = self.join(lower_bound, node.lower_bound)
1328
- upper_bound = self.meet(upper_bound, node.upper_bound)
1329
- # TODO: Support variables that are accessed via differently sized pointers
1373
+ node_size = node.size
1374
+ if node_size is not None:
1375
+ node_sizes.add(node_size)
1376
+ if len(node_sizes) > 1:
1377
+ # multi-sized reads - cannot converge to a reasonable type
1378
+ result = Bottom_
1379
+ else:
1380
+ for node in nodes:
1381
+ lower_bound = self.join(lower_bound, node.lower_bound)
1382
+ upper_bound = self.meet(upper_bound, node.upper_bound)
1383
+ result = lower_bound if not isinstance(lower_bound, BottomType) else upper_bound
1330
1384
 
1331
- result = lower_bound if not isinstance(lower_bound, BottomType) else upper_bound
1332
1385
  for node in nodes:
1333
1386
  solution[node.typevar] = result
1334
1387
  self._solution_cache[node.typevar] = result
@@ -1386,3 +1439,12 @@ class SimpleSolver:
1386
1439
  if self.bits == 64:
1387
1440
  return Pointer64
1388
1441
  raise NotImplementedError(f"Unsupported bits {self.bits}")
1442
+
1443
+ @staticmethod
1444
+ def dump_constraint_graph(graph: networkx.DiGraph, filename: str) -> None:
1445
+ """
1446
+ Dump the constraint graph to a file.
1447
+ """
1448
+ from networkx.drawing.nx_agraph import write_dot # pylint:disable=import-outside-toplevel
1449
+
1450
+ write_dot(graph, filename)
@@ -100,7 +100,8 @@ class Typehoon(Analysis):
100
100
  and not isinstance(type_.pts_to, SimTypeArray)
101
101
  ):
102
102
  type_ = type_.pts_to
103
- type_candidates.append(type_)
103
+ if type_ is not None:
104
+ type_candidates.append(type_)
104
105
 
105
106
  # determine the best type - this logic can be made better!
106
107
  if not type_candidates:
@@ -9,10 +9,10 @@ import claripy
9
9
  from unique_log_filter import UniqueLogFilter
10
10
 
11
11
  from angr.engines.light.engine import SimEngineNostmtAIL
12
- from angr.procedures import SIM_LIBRARIES, SIM_TYPE_COLLECTIONS
13
- from angr.sim_type import SimTypeFunction, dereference_simtype
12
+ from angr.sim_type import SimTypeFunction
14
13
  from angr.analyses.typehoon import typeconsts, typevars
15
14
  from angr.analyses.typehoon.lifter import TypeLifter
15
+ from angr.utils.types import dereference_simtype_by_lib
16
16
  from .engine_base import SimEngineVRBase, RichR
17
17
 
18
18
  if TYPE_CHECKING:
@@ -190,17 +190,11 @@ class SimEngineVRAIL(
190
190
 
191
191
  if prototype is not None and args:
192
192
  # add type constraints
193
-
194
- type_collections = []
195
- if prototype_libname is not None:
196
- for prototype_lib in SIM_LIBRARIES[prototype_libname]:
197
- if prototype_lib.type_collection_names:
198
- for typelib_name in prototype_lib.type_collection_names:
199
- type_collections.append(SIM_TYPE_COLLECTIONS[typelib_name])
200
-
201
193
  for arg, arg_type in zip(args, prototype.args):
202
194
  if arg.typevar is not None:
203
- arg_type = dereference_simtype(arg_type, type_collections).with_arch(arg_type._arch)
195
+ arg_type = (
196
+ dereference_simtype_by_lib(arg_type, prototype_libname) if prototype_libname else arg_type
197
+ )
204
198
  arg_ty = TypeLifter(self.arch.bits).lift(arg_type)
205
199
  type_constraint = typevars.Subtype(arg.typevar, arg_ty)
206
200
  self.state.add_type_constraint(type_constraint)
@@ -209,7 +203,7 @@ class SimEngineVRAIL(
209
203
 
210
204
  def _handle_stmt_Call(self, stmt):
211
205
  target = stmt.target
212
- args = []
206
+ args: list[RichR] = []
213
207
  if stmt.args:
214
208
  for arg in stmt.args:
215
209
  self._reference_spoffset = True
@@ -283,22 +277,17 @@ class SimEngineVRAIL(
283
277
 
284
278
  if prototype is not None and args:
285
279
  # add type constraints
286
-
287
- type_collections = []
288
- if prototype_libname is not None:
289
- for prototype_lib in SIM_LIBRARIES[prototype_libname]:
290
- if prototype_lib.type_collection_names:
291
- for typelib_name in prototype_lib.type_collection_names:
292
- type_collections.append(SIM_TYPE_COLLECTIONS[typelib_name])
293
-
294
280
  for arg, arg_type in zip(args, prototype.args):
295
281
  if arg.typevar is not None:
296
- arg_type = dereference_simtype(arg_type, type_collections).with_arch(arg_type._arch)
282
+ arg_type = (
283
+ dereference_simtype_by_lib(arg_type, prototype_libname) if prototype_libname else arg_type
284
+ )
297
285
  arg_ty = TypeLifter(self.arch.bits).lift(arg_type)
298
- if isinstance(arg_ty, typevars.TypeConstraint) and isinstance(arg.typevar, typevars.TypeConstraint):
299
- continue
300
- type_constraint = typevars.Subtype(arg.typevar, arg_ty)
301
- self.state.add_type_constraint(type_constraint)
286
+ if arg.typevar is not None and isinstance(
287
+ arg_ty, (typeconsts.TypeConstant, typevars.TypeVariable, typevars.DerivedTypeVariable)
288
+ ):
289
+ type_constraint = typevars.Subtype(arg.typevar, arg_ty)
290
+ self.state.add_type_constraint(type_constraint)
302
291
 
303
292
  def _handle_stmt_Return(self, stmt):
304
293
  if stmt.ret_exprs:
@@ -47,7 +47,7 @@ class RichR(Generic[RichRT_co]):
47
47
  ):
48
48
  self.data = data
49
49
  self.variable = variable
50
- self.typevar = typevar
50
+ self.typevar: typeconsts.TypeConstant | typevars.TypeVariable | None = typevar
51
51
  self.type_constraints = type_constraints
52
52
 
53
53
  @property
@@ -127,7 +127,7 @@ class Function(Serializable):
127
127
  self._retout_sites: set[BlockNode] = set()
128
128
  # block nodes (basic block nodes) at whose ends the function terminates
129
129
  # in theory, if everything works fine, endpoints == ret_sites | jumpout_sites | callout_sites
130
- self._endpoints = defaultdict(set)
130
+ self._endpoints: defaultdict[str, set[BlockNode]] = defaultdict(set)
131
131
 
132
132
  self._call_sites = {}
133
133
  self.addr = addr
@@ -1358,7 +1358,7 @@ class Function(Serializable):
1358
1358
  return
1359
1359
 
1360
1360
  graph = self.transition_graph
1361
- end_addresses = defaultdict(list)
1361
+ end_addresses: defaultdict[int, list[BlockNode]] = defaultdict(list)
1362
1362
 
1363
1363
  for block in self.nodes:
1364
1364
  if isinstance(block, BlockNode):
@@ -1456,7 +1456,13 @@ class Function(Serializable):
1456
1456
  )
1457
1457
  else:
1458
1458
  # We gotta create a new one
1459
- l.error("normalize(): Please report it to Fish/maybe john.")
1459
+ l.error("normalize(): Please report it to Fish.")
1460
+
1461
+ # update endpoints
1462
+ for sortset in self._endpoints.values():
1463
+ if n in sortset:
1464
+ sortset.remove(n)
1465
+ sortset.add(smallest_node)
1460
1466
 
1461
1467
  end_addresses[end_addr] = [smallest_node]
1462
1468
 
@@ -1680,7 +1686,7 @@ class Function(Serializable):
1680
1686
  n = separator
1681
1687
  if must_disambiguate_by_addr:
1682
1688
  n += hex(self.addr) + separator
1683
- elif self.binary is not self.project.loader.main_object:
1689
+ elif self.binary is not self.project.loader.main_object and self.binary_name is not None:
1684
1690
  n += self.binary_name + separator
1685
1691
  return n + (display_name or self.name)
1686
1692
 
Binary file
angr/sim_type.py CHANGED
@@ -7,7 +7,7 @@ import re
7
7
  import logging
8
8
  from collections import OrderedDict, defaultdict, ChainMap
9
9
  from collections.abc import Iterable
10
- from typing import Literal, Any, TYPE_CHECKING, cast, overload
10
+ from typing import Literal, Any, cast, overload
11
11
 
12
12
  from archinfo import Endness, Arch
13
13
  import claripy
@@ -17,12 +17,9 @@ import cxxheaderparser.types
17
17
  import pycparser
18
18
  from pycparser import c_ast
19
19
 
20
- from angr.errors import AngrMissingTypeError, AngrTypeError
20
+ from angr.errors import AngrTypeError
21
21
  from angr.sim_state import SimState
22
22
 
23
- if TYPE_CHECKING:
24
- from angr.procedures.definitions import SimTypeCollection
25
-
26
23
  StoreType = int | claripy.ast.BV
27
24
 
28
25
  l = logging.getLogger(name=__name__)
@@ -324,7 +321,7 @@ class SimTypeReg(SimType):
324
321
  with contextlib.suppress(AttributeError):
325
322
  value = value.ast # type: ignore
326
323
  if isinstance(value, claripy.ast.Bits): # pylint:disable=isinstance-second-argument-not-valid-type
327
- if value.size() != self.size:
324
+ if value.size() != self.size: # type: ignore
328
325
  raise ValueError("size of expression is wrong size for type")
329
326
  elif isinstance(value, int):
330
327
  value = claripy.BVV(value, self.size)
@@ -383,7 +380,7 @@ class SimTypeNum(SimType):
383
380
  store_endness = state.arch.memory_endness
384
381
 
385
382
  if isinstance(value, claripy.ast.Bits): # pylint:disable=isinstance-second-argument-not-valid-type
386
- if value.size() != self.size:
383
+ if value.size() != self.size: # type: ignore
387
384
  raise ValueError("size of expression is wrong size for type")
388
385
  elif isinstance(value, int) and self.size is not None:
389
386
  value = claripy.BVV(value, self.size)
@@ -505,7 +502,12 @@ class SimTypeFixedSizeInt(SimTypeInt):
505
502
  _fixed_size: int = 32
506
503
 
507
504
  def c_repr(
508
- self, name=None, full=0, memo=None, indent=0, name_parens: bool = True # pylint:disable=unused-argument
505
+ self,
506
+ name=None,
507
+ full=0,
508
+ memo=None,
509
+ indent: int | None = 0,
510
+ name_parens: bool = True, # pylint:disable=unused-argument
509
511
  ):
510
512
  out = self._base_name
511
513
  if not self.signed:
@@ -1653,7 +1655,7 @@ class SimUnion(NamedTypeMixin, SimType):
1653
1655
  def size(self):
1654
1656
  if self._arch is None:
1655
1657
  raise ValueError("Can't tell my size without an arch!")
1656
- member_sizes = [ty.size for ty in self.members.values() if not isinstance(ty, SimTypeBottom)]
1658
+ member_sizes: list[int] = [ty.size for ty in self.members.values() if not isinstance(ty, SimTypeBottom)]
1657
1659
  # fall back to word size in case all members are SimTypeBottom
1658
1660
  return max(member_sizes) if member_sizes else self._arch.bytes
1659
1661
 
@@ -3652,67 +3654,6 @@ def parse_cpp_file(cpp_decl, with_param_names: bool = False):
3652
3654
  return func_decls, {}
3653
3655
 
3654
3656
 
3655
- def dereference_simtype(
3656
- t: SimType, type_collections: list[SimTypeCollection], memo: dict[str, SimType] | None = None
3657
- ) -> SimType:
3658
- if memo is None:
3659
- memo = {}
3660
-
3661
- if isinstance(t, SimTypeRef):
3662
- real_type = None
3663
-
3664
- if t.name in memo:
3665
- return memo[t.name]
3666
-
3667
- if type_collections and t.name is not None:
3668
- for tc in type_collections:
3669
- try:
3670
- real_type = tc.get(t.name)
3671
- break
3672
- except AngrMissingTypeError:
3673
- continue
3674
- if real_type is None:
3675
- raise AngrMissingTypeError(f"Missing type {t.name}")
3676
- return dereference_simtype(real_type, type_collections, memo=memo)
3677
-
3678
- # the following code prepares a real_type SimType object that will be returned at the end of this method
3679
- if isinstance(t, SimStruct):
3680
- if t.name in memo:
3681
- return memo[t.name]
3682
-
3683
- real_type = t.copy()
3684
- if not t.anonymous:
3685
- memo[t.name] = real_type
3686
- fields = OrderedDict((k, dereference_simtype(v, type_collections, memo=memo)) for k, v in t.fields.items())
3687
- real_type.fields = fields
3688
- elif isinstance(t, SimTypePointer):
3689
- real_pts_to = dereference_simtype(t.pts_to, type_collections, memo=memo)
3690
- real_type = t.copy()
3691
- real_type.pts_to = real_pts_to
3692
- elif isinstance(t, SimTypeArray):
3693
- real_elem_type = dereference_simtype(t.elem_type, type_collections, memo=memo)
3694
- real_type = t.copy()
3695
- real_type.elem_type = real_elem_type
3696
- elif isinstance(t, SimUnion):
3697
- real_members = {k: dereference_simtype(v, type_collections, memo=memo) for k, v in t.members.items()}
3698
- real_type = t.copy()
3699
- real_type.members = real_members
3700
- elif isinstance(t, SimTypeFunction):
3701
- real_args = [dereference_simtype(arg, type_collections, memo=memo) for arg in t.args]
3702
- real_return_type = (
3703
- dereference_simtype(t.returnty, type_collections, memo=memo) if t.returnty is not None else None
3704
- )
3705
- real_type = t.copy()
3706
- real_type.args = tuple(real_args)
3707
- real_type.returnty = real_return_type
3708
- else:
3709
- return t
3710
-
3711
- if t._arch is not None:
3712
- real_type = real_type.with_arch(t._arch)
3713
- return real_type
3714
-
3715
-
3716
3657
  if pycparser is not None:
3717
3658
  _accepts_scope_stack()
3718
3659