angr 9.2.112__py3-none-macosx_11_0_arm64.whl → 9.2.113__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/cfg/cfg_base.py +3 -0
  3. angr/analyses/decompiler/condition_processor.py +9 -2
  4. angr/analyses/decompiler/optimization_passes/__init__.py +3 -1
  5. angr/analyses/decompiler/optimization_passes/const_prop_reverter.py +367 -0
  6. angr/analyses/decompiler/optimization_passes/deadblock_remover.py +1 -1
  7. angr/analyses/decompiler/optimization_passes/lowered_switch_simplifier.py +99 -12
  8. angr/analyses/decompiler/optimization_passes/optimization_pass.py +79 -9
  9. angr/analyses/decompiler/optimization_passes/return_duplicator_base.py +21 -0
  10. angr/analyses/decompiler/optimization_passes/return_duplicator_low.py +111 -9
  11. angr/analyses/decompiler/redundant_label_remover.py +17 -0
  12. angr/analyses/decompiler/seq_cf_structure_counter.py +37 -0
  13. angr/analyses/decompiler/structured_codegen/c.py +4 -5
  14. angr/analyses/decompiler/structuring/phoenix.py +3 -3
  15. angr/analyses/reaching_definitions/rd_state.py +2 -0
  16. angr/analyses/reaching_definitions/reaching_definitions.py +7 -0
  17. angr/angrdb/serializers/loader.py +91 -7
  18. angr/calling_conventions.py +11 -9
  19. angr/knowledge_plugins/key_definitions/live_definitions.py +5 -0
  20. angr/knowledge_plugins/propagations/states.py +3 -2
  21. angr/lib/angr_native.dylib +0 -0
  22. angr/procedures/stubs/ReturnUnconstrained.py +1 -2
  23. angr/procedures/stubs/syscall_stub.py +1 -2
  24. angr/sim_type.py +354 -136
  25. angr/state_plugins/debug_variables.py +2 -2
  26. angr/storage/memory_mixins/multi_value_merger_mixin.py +12 -2
  27. {angr-9.2.112.dist-info → angr-9.2.113.dist-info}/METADATA +6 -6
  28. {angr-9.2.112.dist-info → angr-9.2.113.dist-info}/RECORD +32 -30
  29. {angr-9.2.112.dist-info → angr-9.2.113.dist-info}/WHEEL +1 -1
  30. {angr-9.2.112.dist-info → angr-9.2.113.dist-info}/LICENSE +0 -0
  31. {angr-9.2.112.dist-info → angr-9.2.113.dist-info}/entry_points.txt +0 -0
  32. {angr-9.2.112.dist-info → angr-9.2.113.dist-info}/top_level.txt +0 -0
angr/sim_type.py CHANGED
@@ -1,30 +1,36 @@
1
- # pylint:disable=abstract-method,line-too-long,missing-class-docstring
1
+ # pylint:disable=abstract-method,line-too-long,missing-class-docstring,wrong-import-position
2
+ from __future__ import annotations
2
3
  from __future__ import annotations
3
4
 
4
5
  from collections import OrderedDict, defaultdict, ChainMap
5
6
  import copy
6
7
  import re
7
- from typing import Any, TYPE_CHECKING
8
+ from typing import Literal, Optional, Any, Union, TYPE_CHECKING, cast, overload
9
+ from collections.abc import Iterable
8
10
  import logging
9
11
 
10
- try:
11
- import pycparser
12
- except ImportError:
13
- pycparser = None
14
-
15
12
  try:
16
13
  import CppHeaderParser
17
14
  except ImportError:
18
15
  CppHeaderParser = None
19
16
 
20
- from archinfo import Endness
17
+ from archinfo import Endness, Arch
21
18
  import claripy
22
19
 
23
- from angr.errors import AngrMissingTypeError
20
+ from angr.errors import AngrMissingTypeError, AngrTypeError
24
21
  from .misc.ux import deprecated
25
22
 
26
23
  if TYPE_CHECKING:
24
+ import pycparser
27
25
  from angr.procedures.definitions import SimTypeCollection
26
+ from angr.storage.memory_mixins import _Coerce
27
+
28
+ StoreType = Union[_Coerce, claripy.ast.BV]
29
+ else:
30
+ try:
31
+ import pycparser
32
+ except ImportError:
33
+ pycparser = None
28
34
 
29
35
 
30
36
  l = logging.getLogger(name=__name__)
@@ -39,18 +45,19 @@ class SimType:
39
45
  SimType exists to track type information for SimProcedures.
40
46
  """
41
47
 
42
- _fields = ()
43
- _arch = None
44
- _size = None
45
- _can_refine_int = False
46
- _base_name = None
47
- base = True
48
+ _fields: tuple[str, ...] = ()
49
+ _arch: Arch | None
50
+ _size: int | None = None
51
+ _can_refine_int: bool = False
52
+ _base_name: str
53
+ base: bool = True
48
54
 
49
55
  def __init__(self, label=None):
50
56
  """
51
57
  :param label: the type label.
52
58
  """
53
59
  self.label = label
60
+ self._arch = None
54
61
 
55
62
  @staticmethod
56
63
  def _simtype_eq(self_type: SimType, other: SimType, avoid: dict[str, set[SimType]] | None) -> bool:
@@ -106,13 +113,11 @@ class SimType:
106
113
  raise KeyError(f"{k} is not a valid refinement")
107
114
 
108
115
  @property
109
- def size(self):
116
+ def size(self) -> int | None:
110
117
  """
111
- The size of the type in bits.
118
+ The size of the type in bits, or None if no size is computable.
112
119
  """
113
- if self._size is not None:
114
- return self._size
115
- return NotImplemented
120
+ return self._size
116
121
 
117
122
  @property
118
123
  def alignment(self):
@@ -121,11 +126,11 @@ class SimType:
121
126
  """
122
127
  if self._arch is None:
123
128
  raise ValueError("Can't tell my alignment without an arch!")
124
- if self.size is NotImplemented:
125
- return NotImplemented
129
+ if self.size is None:
130
+ raise AngrTypeError("Cannot compute the alignment of a type with no size")
126
131
  return self.size // self._arch.byte_width
127
132
 
128
- def with_arch(self, arch):
133
+ def with_arch(self, arch: Arch | None):
129
134
  if arch is None:
130
135
  return self
131
136
  if self._arch is not None and self._arch == arch:
@@ -141,7 +146,9 @@ class SimType:
141
146
  def _init_str(self):
142
147
  return f"NotImplemented({self.__class__.__name__})"
143
148
 
144
- def c_repr(self, name=None, full=0, memo=None, indent=0): # pylint:disable=unused-argument
149
+ def c_repr(
150
+ self, name=None, full=0, memo=None, indent: int | None = 0, name_parens: bool = True
151
+ ): # pylint: disable=unused-argument
145
152
  if name is None:
146
153
  return repr(self)
147
154
  else:
@@ -150,7 +157,13 @@ class SimType:
150
157
  def copy(self):
151
158
  raise NotImplementedError()
152
159
 
153
- def extract_claripy(self, bits):
160
+ def extract(self, state: SimState, addr, concrete: bool = False) -> Any:
161
+ raise NotImplementedError
162
+
163
+ def store(self, state: SimState, addr, value: Any):
164
+ raise NotImplementedError
165
+
166
+ def extract_claripy(self, bits) -> Any:
154
167
  """
155
168
  Given a bitvector `bits` which was loaded from memory in a big-endian fashion, return a more appropriate or
156
169
  structured representation of the data.
@@ -172,6 +185,15 @@ class TypeRef(SimType):
172
185
  self.type = ty
173
186
  self._name = name
174
187
 
188
+ @property
189
+ def type(self):
190
+ return self._type
191
+
192
+ @type.setter
193
+ def type(self, val):
194
+ self._type = val
195
+ self._arch = val._arch
196
+
175
197
  @property
176
198
  def name(self):
177
199
  """
@@ -189,10 +211,6 @@ class TypeRef(SimType):
189
211
  def __repr__(self):
190
212
  return self.name
191
213
 
192
- @property
193
- def _arch(self):
194
- return self.type._arch
195
-
196
214
  @property
197
215
  def size(self):
198
216
  return self.type.size
@@ -278,7 +296,7 @@ class SimTypeTop(SimType):
278
296
 
279
297
  _fields = ("size",)
280
298
 
281
- def __init__(self, size=None, label=None):
299
+ def __init__(self, size: int | None = None, label=None):
282
300
  SimType.__init__(self, label)
283
301
  self._size = size
284
302
 
@@ -296,7 +314,7 @@ class SimTypeReg(SimType):
296
314
 
297
315
  _fields = ("size",)
298
316
 
299
- def __init__(self, size, label=None):
317
+ def __init__(self, size: int | None, label=None):
300
318
  """
301
319
  :param label: the type label.
302
320
  :param size: the size of the type (e.g. 32bit, 8bit, etc.).
@@ -307,19 +325,10 @@ class SimTypeReg(SimType):
307
325
  def __repr__(self):
308
326
  return f"reg{self.size}_t"
309
327
 
310
- def extract(self, state, addr, concrete=False):
311
- # TODO: EDG says this looks dangerously closed-minded. Just in case...
312
- assert self.size % state.arch.byte_width == 0
313
-
314
- out = state.memory.load(addr, self.size // state.arch.byte_width, endness=state.arch.memory_endness)
315
- if not concrete:
316
- return out
317
- return state.solver.eval(out)
318
-
319
- def store(self, state, addr, value):
328
+ def store(self, state, addr, value: StoreType):
320
329
  store_endness = state.arch.memory_endness
321
330
  try:
322
- value = value.ast
331
+ value = value.ast # type: ignore
323
332
  except AttributeError:
324
333
  pass
325
334
  if isinstance(value, claripy.ast.Bits): # pylint:disable=isinstance-second-argument-not-valid-type
@@ -345,7 +354,7 @@ class SimTypeNum(SimType):
345
354
 
346
355
  _fields = SimType._fields + ("signed", "size")
347
356
 
348
- def __init__(self, size, signed=True, label=None):
357
+ def __init__(self, size: int, signed=True, label=None):
349
358
  """
350
359
  :param size: The size of the integer, in bits
351
360
  :param signed: Whether the integer is signed or not
@@ -355,9 +364,20 @@ class SimTypeNum(SimType):
355
364
  self._size = size
356
365
  self.signed = signed
357
366
 
367
+ @property
368
+ def size(self) -> int:
369
+ assert self._size is not None
370
+ return self._size
371
+
358
372
  def __repr__(self):
359
373
  return "{}int{}_t".format("" if self.signed else "u", self.size)
360
374
 
375
+ @overload
376
+ def extract(self, state, addr, concrete: Literal[False] = ...) -> claripy.ast.BV: ...
377
+
378
+ @overload
379
+ def extract(self, state, addr, concrete: Literal[True] = ...) -> int: ...
380
+
361
381
  def extract(self, state, addr, concrete=False):
362
382
  out = state.memory.load(addr, self.size // state.arch.byte_width, endness=state.arch.memory_endness)
363
383
  if not concrete:
@@ -367,14 +387,14 @@ class SimTypeNum(SimType):
367
387
  n -= 1 << (self.size)
368
388
  return n
369
389
 
370
- def store(self, state, addr, value):
390
+ def store(self, state, addr, value: StoreType):
371
391
  store_endness = state.arch.memory_endness
372
392
 
373
393
  if isinstance(value, claripy.ast.Bits): # pylint:disable=isinstance-second-argument-not-valid-type
374
394
  if value.size() != self.size:
375
395
  raise ValueError("size of expression is wrong size for type")
376
- elif isinstance(value, int):
377
- value = state.solver.BVV(value, self.size)
396
+ elif isinstance(value, int) and self.size is not None:
397
+ value = claripy.BVV(value, self.size)
378
398
  elif isinstance(value, bytes):
379
399
  store_endness = "Iend_BE"
380
400
  else:
@@ -426,8 +446,14 @@ class SimTypeInt(SimTypeReg):
426
446
  raise ValueError("Can't tell my size without an arch!")
427
447
  try:
428
448
  return self._arch.sizeof[self._base_name]
429
- except KeyError as ex:
430
- raise ValueError(f"Arch {self._arch.name} doesn't have its {self._base_name} type defined!") from ex
449
+ except KeyError as e:
450
+ raise ValueError(f"Arch {self._arch.name} doesn't have its {self._base_name} type defined!") from e
451
+
452
+ @overload
453
+ def extract(self, state, addr, concrete: Literal[False] = ...) -> claripy.ast.BV: ...
454
+
455
+ @overload
456
+ def extract(self, state, addr, concrete: Literal[True] = ...) -> int: ...
431
457
 
432
458
  def extract(self, state, addr, concrete=False):
433
459
  out = state.memory.load(addr, self.size // state.arch.byte_width, endness=state.arch.memory_endness)
@@ -488,13 +514,13 @@ class SimTypeChar(SimTypeReg):
488
514
  :param label: the type label.
489
515
  """
490
516
  # FIXME: Now the size of a char is state-dependent.
491
- SimTypeReg.__init__(self, 8, label=label)
517
+ super().__init__(8, label=label)
492
518
  self.signed = signed
493
519
 
494
- def __repr__(self):
520
+ def __repr__(self) -> str:
495
521
  return "char"
496
522
 
497
- def store(self, state, addr, value):
523
+ def store(self, state, addr, value: StoreType):
498
524
  # FIXME: This is a hack.
499
525
  self._size = state.arch.byte_width
500
526
  try:
@@ -506,13 +532,19 @@ class SimTypeChar(SimTypeReg):
506
532
  else:
507
533
  raise
508
534
 
509
- def extract(self, state, addr, concrete=False):
535
+ @overload
536
+ def extract(self, state, addr, concrete: Literal[False] = ...) -> claripy.ast.BV: ...
537
+
538
+ @overload
539
+ def extract(self, state, addr, concrete: Literal[True] = ...) -> bytes: ...
540
+
541
+ def extract(self, state, addr, concrete: bool = False) -> claripy.ast.BV | bytes:
510
542
  # FIXME: This is a hack.
511
543
  self._size = state.arch.byte_width
512
544
 
513
- out = super().extract(state, addr, concrete)
545
+ out = state.memory.load(addr, 1, endness=state.arch.memory_endness)
514
546
  if concrete:
515
- return bytes([out])
547
+ return bytes(cast(list[int], [state.solver.eval(out)]))
516
548
  return out
517
549
 
518
550
  def _init_str(self):
@@ -542,7 +574,7 @@ class SimTypeWideChar(SimTypeReg):
542
574
  def __repr__(self):
543
575
  return "wchar"
544
576
 
545
- def store(self, state, addr, value):
577
+ def store(self, state, addr, value: StoreType):
546
578
  self._size = state.arch.byte_width
547
579
  try:
548
580
  super().store(state, addr, value)
@@ -553,7 +585,7 @@ class SimTypeWideChar(SimTypeReg):
553
585
  else:
554
586
  raise
555
587
 
556
- def extract(self, state, addr, concrete=False):
588
+ def extract(self, state, addr, concrete=False) -> Any:
557
589
  self._size = state.arch.byte_width
558
590
 
559
591
  out = super().extract(state, addr, concrete)
@@ -571,14 +603,30 @@ class SimTypeWideChar(SimTypeReg):
571
603
  return self.__class__(signed=self.signed, label=self.label)
572
604
 
573
605
 
574
- class SimTypeBool(SimTypeChar):
606
+ class SimTypeBool(SimTypeReg):
575
607
  _base_name = "bool"
576
608
 
609
+ def __init__(self, signed=True, label=None):
610
+ """
611
+ :param label: the type label.
612
+ """
613
+ # FIXME: Now the size of a char is state-dependent.
614
+ super().__init__(8, label=label)
615
+ self.signed = signed
616
+
577
617
  def __repr__(self):
578
618
  return "bool"
579
619
 
580
- def store(self, state, addr, value):
581
- return super().store(state, addr, int(value))
620
+ def store(self, state, addr, value: StoreType | bool):
621
+ if isinstance(value, bool):
622
+ value = int(value)
623
+ return super().store(state, addr, value)
624
+
625
+ @overload
626
+ def extract(self, state, addr, concrete: Literal[False] = ...) -> claripy.ast.Bool: ...
627
+
628
+ @overload
629
+ def extract(self, state, addr, concrete: Literal[True] = ...) -> bool: ...
582
630
 
583
631
  def extract(self, state, addr, concrete=False):
584
632
  ver = super().extract(state, addr, concrete)
@@ -589,6 +637,9 @@ class SimTypeBool(SimTypeChar):
589
637
  def _init_str(self):
590
638
  return f"{self.__class__.__name__}()"
591
639
 
640
+ def copy(self):
641
+ return self.__class__(signed=self.signed, label=self.label)
642
+
592
643
 
593
644
  class SimTypeFd(SimTypeReg):
594
645
  """
@@ -605,6 +656,10 @@ class SimTypeFd(SimTypeReg):
605
656
  # TODO: That's so closed-minded!
606
657
  super().__init__(32, label=label)
607
658
 
659
+ @property
660
+ def size(self):
661
+ return 32
662
+
608
663
  def __repr__(self):
609
664
  return "fd_t"
610
665
 
@@ -617,6 +672,21 @@ class SimTypeFd(SimTypeReg):
617
672
  ('label="%s"' % self.label) if self.label is not None else "",
618
673
  )
619
674
 
675
+ @overload
676
+ def extract(self, state, addr, concrete: Literal[False] = ...) -> claripy.ast.BV: ...
677
+
678
+ @overload
679
+ def extract(self, state, addr, concrete: Literal[True] = ...) -> int: ...
680
+
681
+ def extract(self, state, addr, concrete=False):
682
+ # TODO: EDG says this looks dangerously closed-minded. Just in case...
683
+ assert self.size % state.arch.byte_width == 0
684
+
685
+ out = state.memory.load(addr, self.size // state.arch.byte_width, endness=state.arch.memory_endness)
686
+ if not concrete:
687
+ return out
688
+ return state.solver.eval(out)
689
+
620
690
 
621
691
  class SimTypePointer(SimTypeReg):
622
692
  """
@@ -677,6 +747,21 @@ class SimTypePointer(SimTypeReg):
677
747
  def copy(self):
678
748
  return SimTypePointer(self.pts_to, label=self.label, offset=self.offset)
679
749
 
750
+ @overload
751
+ def extract(self, state, addr, concrete: Literal[False] = ...) -> claripy.ast.BV: ...
752
+
753
+ @overload
754
+ def extract(self, state, addr, concrete: Literal[True] = ...) -> int: ...
755
+
756
+ def extract(self, state, addr, concrete=False):
757
+ # TODO: EDG says this looks dangerously closed-minded. Just in case...
758
+ assert self.size % state.arch.byte_width == 0
759
+
760
+ out = state.memory.load(addr, self.size // state.arch.byte_width, endness=state.arch.memory_endness)
761
+ if not concrete:
762
+ return out
763
+ return state.solver.eval(out)
764
+
680
765
 
681
766
  class SimTypeReference(SimTypeReg):
682
767
  """
@@ -720,6 +805,21 @@ class SimTypeReference(SimTypeReg):
720
805
  def copy(self):
721
806
  return SimTypeReference(self.refs, label=self.label)
722
807
 
808
+ @overload
809
+ def extract(self, state, addr, concrete: Literal[False] = ...) -> claripy.ast.BV: ...
810
+
811
+ @overload
812
+ def extract(self, state, addr, concrete: Literal[True] = ...) -> int: ...
813
+
814
+ def extract(self, state, addr, concrete=False):
815
+ # TODO: EDG says this looks dangerously closed-minded. Just in case...
816
+ assert self.size % state.arch.byte_width == 0
817
+
818
+ out = state.memory.load(addr, self.size // state.arch.byte_width, endness=state.arch.memory_endness)
819
+ if not concrete:
820
+ return out
821
+ return state.solver.eval(out)
822
+
723
823
 
724
824
  class SimTypeArray(SimType):
725
825
  """
@@ -752,6 +852,8 @@ class SimTypeArray(SimType):
752
852
  def size(self):
753
853
  if self.length is None:
754
854
  return 0
855
+ if self.elem_type.size is None:
856
+ return None
755
857
  return self.elem_type.size * self.length
756
858
 
757
859
  @property
@@ -773,14 +875,27 @@ class SimTypeArray(SimType):
773
875
  addr=view._addr + k * (self.elem_type.size // view.state.arch.byte_width), ty=self.elem_type
774
876
  )
775
877
 
878
+ @overload
879
+ def extract(self, state, addr, concrete: Literal[False] = ...) -> list[Any]: # associated types...
880
+ ...
881
+
882
+ @overload
883
+ def extract(self, state, addr, concrete: Literal[True] = ...) -> list[Any]: ...
884
+
776
885
  def extract(self, state, addr, concrete=False):
886
+ if self.length is None:
887
+ return []
888
+ if self.elem_type.size is None:
889
+ return None
777
890
  return [
778
891
  self.elem_type.extract(state, addr + i * (self.elem_type.size // state.arch.byte_width), concrete)
779
892
  for i in range(self.length)
780
893
  ]
781
894
 
782
- def store(self, state, addr, values):
783
- for i, val in enumerate(values):
895
+ def store(self, state, addr, value: list[StoreType]):
896
+ if self.elem_type.size is None:
897
+ raise AngrTypeError("Cannot call store on an array of unsized types")
898
+ for i, val in enumerate(value):
784
899
  self.elem_type.store(state, addr + i * (self.elem_type.size // state.arch.byte_width), val)
785
900
 
786
901
  def _init_str(self):
@@ -795,7 +910,7 @@ class SimTypeArray(SimType):
795
910
  SimTypeFixedSizeArray = SimTypeArray
796
911
 
797
912
 
798
- class SimTypeString(NamedTypeMixin, SimTypeArray):
913
+ class SimTypeString(NamedTypeMixin, SimType):
799
914
  """
800
915
  SimTypeString is a type that represents a C-style string,
801
916
  i.e. a NUL-terminated array of bytes.
@@ -803,16 +918,31 @@ class SimTypeString(NamedTypeMixin, SimTypeArray):
803
918
 
804
919
  _fields = SimTypeArray._fields + ("length",)
805
920
 
806
- def __init__(self, length=None, label=None, name: str | None = None):
921
+ def __init__(self, length: int | None = None, label=None, name: str | None = None):
807
922
  """
808
923
  :param label: The type label.
809
924
  :param length: An expression of the length of the string, if known.
810
925
  """
811
- super().__init__(SimTypeChar(), label=label, length=length, name=name)
926
+ super().__init__(label=label, name=name)
927
+ self.elem_type = SimTypeChar()
928
+ self.length = length
812
929
 
813
930
  def __repr__(self):
814
931
  return "string_t"
815
932
 
933
+ def c_repr(self, name=None, full=0, memo=None, indent=0):
934
+ if name is None:
935
+ return repr(self)
936
+
937
+ name = "{}[{}]".format(name, self.length if self.length is not None else "")
938
+ return self.elem_type.c_repr(name, full, memo, indent)
939
+
940
+ @overload
941
+ def extract(self, state, addr, concrete: Literal[False] = ...) -> claripy.ast.BV: ...
942
+
943
+ @overload
944
+ def extract(self, state, addr, concrete: Literal[True] = ...) -> bytes: ...
945
+
816
946
  def extract(self, state: SimState, addr, concrete=False):
817
947
  if self.length is None:
818
948
  out = None
@@ -853,20 +983,37 @@ class SimTypeString(NamedTypeMixin, SimTypeArray):
853
983
  def copy(self):
854
984
  return SimTypeString(length=self.length, label=self.label, name=self.name)
855
985
 
986
+ def _init_str(self):
987
+ return "{}({}, {}{})".format(
988
+ self.__class__.__name__,
989
+ self.elem_type._init_str(),
990
+ self.length,
991
+ f", {self.label}" if self.label is not None else "",
992
+ )
993
+
856
994
 
857
- class SimTypeWString(NamedTypeMixin, SimTypeArray):
995
+ class SimTypeWString(NamedTypeMixin, SimType):
858
996
  """
859
997
  A wide-character null-terminated string, where each character is 2 bytes.
860
998
  """
861
999
 
862
1000
  _fields = SimTypeArray._fields + ("length",)
863
1001
 
864
- def __init__(self, length=None, label=None, name: str | None = None):
865
- super().__init__(SimTypeNum(16, False), label=label, length=length, name=name)
1002
+ def __init__(self, length: int | None = None, label=None, name: str | None = None):
1003
+ super().__init__(label=label, name=name)
1004
+ self.elem_type = SimTypeNum(16, False)
1005
+ self.length = length
866
1006
 
867
1007
  def __repr__(self):
868
1008
  return "wstring_t"
869
1009
 
1010
+ def c_repr(self, name=None, full=0, memo=None, indent=0):
1011
+ if name is None:
1012
+ return repr(self)
1013
+
1014
+ name = "{}[{}]".format(name, self.length if self.length is not None else "")
1015
+ return self.elem_type.c_repr(name, full, memo, indent)
1016
+
870
1017
  def extract(self, state, addr, concrete=False):
871
1018
  if self.length is None:
872
1019
  out = None
@@ -891,6 +1038,9 @@ class SimTypeWString(NamedTypeMixin, SimTypeArray):
891
1038
  for x in out.chop(16)
892
1039
  )
893
1040
 
1041
+ def store(self, state, addr, value):
1042
+ raise NotImplementedError
1043
+
894
1044
  _can_refine_int = True
895
1045
 
896
1046
  def _refine(self, view, k):
@@ -912,6 +1062,14 @@ class SimTypeWString(NamedTypeMixin, SimTypeArray):
912
1062
  def copy(self):
913
1063
  return SimTypeWString(length=self.length, label=self.label, name=self.name)
914
1064
 
1065
+ def _init_str(self):
1066
+ return "{}({}, {}{})".format(
1067
+ self.__class__.__name__,
1068
+ self.elem_type._init_str(),
1069
+ self.length,
1070
+ f", {self.label}" if self.label is not None else "",
1071
+ )
1072
+
915
1073
 
916
1074
  class SimTypeFunction(SimType):
917
1075
  """
@@ -922,7 +1080,14 @@ class SimTypeFunction(SimType):
922
1080
  _fields = ("args", "returnty")
923
1081
  base = False
924
1082
 
925
- def __init__(self, args: list[SimType], returnty: SimType | None, label=None, arg_names=None, variadic=False):
1083
+ def __init__(
1084
+ self,
1085
+ args: Iterable[SimType],
1086
+ returnty: SimType | None,
1087
+ label=None,
1088
+ arg_names: Iterable[str] | None = None,
1089
+ variadic=False,
1090
+ ):
926
1091
  """
927
1092
  :param label: The type label
928
1093
  :param args: A tuple of types representing the arguments to the function
@@ -930,9 +1095,9 @@ class SimTypeFunction(SimType):
930
1095
  :param variadic: Whether the function accepts varargs
931
1096
  """
932
1097
  super().__init__(label=label)
933
- self.args: list[SimType] = args
1098
+ self.args: tuple[SimType, ...] = tuple(args)
934
1099
  self.returnty: SimType | None = returnty
935
- self.arg_names = arg_names if arg_names else ()
1100
+ self.arg_names = tuple(arg_names) if arg_names else ()
936
1101
  self.variadic = variadic
937
1102
 
938
1103
  def __hash__(self):
@@ -983,7 +1148,7 @@ class SimTypeFunction(SimType):
983
1148
  return "{}([{}], {}{}{}{})".format(
984
1149
  self.__class__.__name__,
985
1150
  ", ".join([arg._init_str() for arg in self.args]),
986
- self.returnty._init_str(),
1151
+ self.returnty._init_str() if self.returnty else "void",
987
1152
  (', label="%s"' % self.label) if self.label else "",
988
1153
  (", arg_names=[%s]" % self._arg_names_str(show_variadic=False)) if self.arg_names else "",
989
1154
  ", variadic=True" if self.variadic else "",
@@ -1005,7 +1170,13 @@ class SimTypeCppFunction(SimTypeFunction):
1005
1170
  """
1006
1171
 
1007
1172
  def __init__(
1008
- self, args, returnty, label=None, arg_names: tuple[str] = None, ctor: bool = False, dtor: bool = False
1173
+ self,
1174
+ args,
1175
+ returnty,
1176
+ label=None,
1177
+ arg_names: Iterable[str] | None = None,
1178
+ ctor: bool = False,
1179
+ dtor: bool = False,
1009
1180
  ):
1010
1181
  super().__init__(args, returnty, label=label, arg_names=arg_names, variadic=False)
1011
1182
  self.ctor = ctor
@@ -1087,18 +1258,24 @@ class SimTypeFloat(SimTypeReg):
1087
1258
  sort = claripy.FSORT_FLOAT
1088
1259
  signed = True
1089
1260
 
1261
+ @property
1262
+ def size(self) -> int:
1263
+ return 32
1264
+
1090
1265
  def extract(self, state, addr, concrete=False):
1091
- itype = claripy.fpToFP(super().extract(state, addr, False), self.sort)
1266
+ itype = claripy.fpToFP(
1267
+ state.memory.load(addr, self.size // state.arch.byte_width, endness=state.arch.memory_endness), self.sort
1268
+ )
1092
1269
  if concrete:
1093
1270
  return state.solver.eval(itype)
1094
1271
  return itype
1095
1272
 
1096
- def store(self, state, addr, value):
1097
- if type(value) in (int, float):
1273
+ def store(self, state, addr, value: StoreType | claripy.ast.FP):
1274
+ if isinstance(value, (int, float)):
1098
1275
  value = claripy.FPV(float(value), self.sort)
1099
- return super().store(state, addr, value)
1276
+ return super().store(state, addr, value) # type: ignore # trust me bro
1100
1277
 
1101
- def __repr__(self):
1278
+ def __repr__(self) -> str:
1102
1279
  return "float"
1103
1280
 
1104
1281
  def _init_str(self):
@@ -1121,6 +1298,10 @@ class SimTypeDouble(SimTypeFloat):
1121
1298
 
1122
1299
  sort = claripy.FSORT_DOUBLE
1123
1300
 
1301
+ @property
1302
+ def size(self) -> int:
1303
+ return 64
1304
+
1124
1305
  def __repr__(self):
1125
1306
  return "double"
1126
1307
 
@@ -1138,12 +1319,12 @@ class SimTypeDouble(SimTypeFloat):
1138
1319
  class SimStruct(NamedTypeMixin, SimType):
1139
1320
  _fields = ("name", "fields")
1140
1321
 
1141
- def __init__(self, fields: dict[str, SimType] | OrderedDict, name=None, pack=False, align=None):
1322
+ def __init__(self, fields: dict[str, SimType] | OrderedDict[str, SimType], name=None, pack=False, align=None):
1142
1323
  super().__init__(None, name="<anon>" if name is None else name)
1143
1324
 
1144
1325
  self._pack = pack
1145
1326
  self._align = align
1146
- self.fields = fields
1327
+ self.fields: OrderedDict[str, SimType] = OrderedDict(fields)
1147
1328
 
1148
1329
  self._arch_memo = {}
1149
1330
 
@@ -1153,10 +1334,13 @@ class SimStruct(NamedTypeMixin, SimType):
1153
1334
 
1154
1335
  @property
1155
1336
  def offsets(self) -> dict[str, int]:
1337
+ if self._arch is None:
1338
+ raise ValueError("Need an arch to calculate offsets")
1339
+
1156
1340
  offsets = {}
1157
1341
  offset_so_far = 0
1158
1342
  for name, ty in self.fields.items():
1159
- if isinstance(ty, SimTypeBottom):
1343
+ if ty.size is None:
1160
1344
  l.warning(
1161
1345
  "Found a bottom field in struct %s. Ignore and increment the offset using the default "
1162
1346
  "element size.",
@@ -1178,7 +1362,7 @@ class SimStruct(NamedTypeMixin, SimType):
1178
1362
 
1179
1363
  return offsets
1180
1364
 
1181
- def extract(self, state, addr, concrete=False):
1365
+ def extract(self, state, addr, concrete=False) -> SimStructValue:
1182
1366
  values = {}
1183
1367
  for name, offset in self.offsets.items():
1184
1368
  ty = self.fields[name]
@@ -1194,7 +1378,7 @@ class SimStruct(NamedTypeMixin, SimType):
1194
1378
  if arch.name in self._arch_memo:
1195
1379
  return self._arch_memo[arch.name]
1196
1380
 
1197
- out = SimStruct(None, name=self.name, pack=self._pack, align=self._align)
1381
+ out = SimStruct({}, name=self.name, pack=self._pack, align=self._align)
1198
1382
  out._arch = arch
1199
1383
  self._arch_memo[arch.name] = out
1200
1384
 
@@ -1202,7 +1386,7 @@ class SimStruct(NamedTypeMixin, SimType):
1202
1386
 
1203
1387
  # Fixup the offsets to byte aligned addresses for all SimTypeNumOffset types
1204
1388
  offset_so_far = 0
1205
- for name, ty in out.fields.items():
1389
+ for _, ty in out.fields.items():
1206
1390
  if isinstance(ty, SimTypeNumOffset):
1207
1391
  out._pack = True
1208
1392
  ty.offset = offset_so_far % arch.byte_width
@@ -1218,15 +1402,13 @@ class SimStruct(NamedTypeMixin, SimType):
1218
1402
 
1219
1403
  indented = " " * indent if indent is not None else ""
1220
1404
  new_indent = indent + 4 if indent is not None else None
1221
- new_indented = " " * new_indent if indent is not None else ""
1405
+ new_indented = " " * new_indent if new_indent is not None else ""
1222
1406
  newline = "\n" if indent is not None else " "
1223
1407
  new_memo = (self,) + (memo if memo is not None else ())
1224
1408
  members = newline.join(
1225
1409
  new_indented + v.c_repr(k, full - 1, new_memo, new_indent) + ";" for k, v in self.fields.items()
1226
1410
  )
1227
- return "struct {} {{{}{}{}{}}}{}".format(
1228
- self.name, newline, members, newline, indented, "" if name is None else " " + name
1229
- )
1411
+ return f"struct {self.name} {{{newline}{members}{newline}{indented}}}{'' if name is None else ' ' + name}"
1230
1412
 
1231
1413
  def __hash__(self):
1232
1414
  return hash((SimStruct, self._name, self._align, self._pack, tuple(self.fields.keys())))
@@ -1235,11 +1417,15 @@ class SimStruct(NamedTypeMixin, SimType):
1235
1417
  def size(self):
1236
1418
  if not self.offsets:
1237
1419
  return 0
1420
+ if self._arch is None:
1421
+ raise ValueError("Need an arch to compute size")
1238
1422
 
1239
1423
  last_name, last_off = list(self.offsets.items())[-1]
1240
1424
  last_type = self.fields[last_name]
1241
1425
  if isinstance(last_type, SimTypeNumOffset):
1242
1426
  return last_off * self._arch.byte_width + (last_type.size + last_type.offset)
1427
+ elif last_type.size is None:
1428
+ raise AngrTypeError("Cannot compute the size of a struct with elements with no size")
1243
1429
  else:
1244
1430
  return last_off * self._arch.byte_width + last_type.size
1245
1431
 
@@ -1259,7 +1445,7 @@ class SimStruct(NamedTypeMixin, SimType):
1259
1445
  ty = self.fields[k]
1260
1446
  return view._deeper(ty=ty, addr=view._addr + offset)
1261
1447
 
1262
- def store(self, state, addr, value):
1448
+ def store(self, state, addr, value: StoreType):
1263
1449
  if type(value) is dict:
1264
1450
  pass
1265
1451
  elif type(value) is SimStructValue:
@@ -1368,10 +1554,10 @@ class SimStructValue:
1368
1554
  for f in self._struct.fields:
1369
1555
  if isinstance(f, NamedTypeMixin) and f.name is None:
1370
1556
  try:
1371
- return f[k]
1557
+ return f[k] # type: ignore # lukas WHAT
1372
1558
  except KeyError:
1373
1559
  continue
1374
- return self._values[k]
1560
+ raise KeyError(k)
1375
1561
 
1376
1562
  return self._values[k]
1377
1563
 
@@ -1431,15 +1617,13 @@ class SimUnion(NamedTypeMixin, SimType):
1431
1617
 
1432
1618
  indented = " " * indent if indent is not None else ""
1433
1619
  new_indent = indent + 4 if indent is not None else None
1434
- new_indented = " " * new_indent if indent is not None else ""
1620
+ new_indented = " " * new_indent if new_indent is not None else ""
1435
1621
  newline = "\n" if indent is not None else " "
1436
1622
  new_memo = (self,) + (memo if memo is not None else ())
1437
1623
  members = newline.join(
1438
1624
  new_indented + v.c_repr(k, full - 1, new_memo, new_indent) + ";" for k, v in self.members.items()
1439
1625
  )
1440
- return "union {} {{{}{}{}{}}}{}".format(
1441
- self.name, newline, members, newline, indented, "" if name is None else " " + name
1442
- )
1626
+ return f"union {self.name} {{{newline}{members}{newline}{indented}}}{'' if name is None else ' ' + name}"
1443
1627
 
1444
1628
  def _init_str(self):
1445
1629
  return '{}({{{}}}, name="{}", label="{}")'.format(
@@ -1498,7 +1682,7 @@ class SimUnionValue:
1498
1682
 
1499
1683
  def __getitem__(self, k):
1500
1684
  if k not in self._values:
1501
- return super().__getitem__(k)
1685
+ raise KeyError(k)
1502
1686
  return self._values[k]
1503
1687
 
1504
1688
  def copy(self):
@@ -1515,7 +1699,7 @@ class SimCppClass(SimStruct):
1515
1699
  pack: bool = False,
1516
1700
  align=None,
1517
1701
  ):
1518
- super().__init__(members, name=name, pack=pack, align=align)
1702
+ super().__init__(members or {}, name=name, pack=pack, align=align)
1519
1703
  # these are actually addresses in the binary
1520
1704
  self.function_members = function_members
1521
1705
  # this should also be added to the fields once we know the offsets of the members of this object
@@ -1528,7 +1712,7 @@ class SimCppClass(SimStruct):
1528
1712
  def __repr__(self):
1529
1713
  return "class %s" % self.name
1530
1714
 
1531
- def extract(self, state, addr, concrete=False):
1715
+ def extract(self, state, addr, concrete=False) -> SimCppClassValue:
1532
1716
  values = {}
1533
1717
  for name, offset in self.offsets.items():
1534
1718
  ty = self.fields[name]
@@ -1540,7 +1724,7 @@ class SimCppClass(SimStruct):
1540
1724
 
1541
1725
  return SimCppClassValue(self, values=values)
1542
1726
 
1543
- def store(self, state, addr, value):
1727
+ def store(self, state, addr, value: StoreType):
1544
1728
  if type(value) is dict:
1545
1729
  pass
1546
1730
  elif type(value) is SimCppClassValue:
@@ -1566,14 +1750,14 @@ class SimCppClass(SimStruct):
1566
1750
  )
1567
1751
 
1568
1752
 
1569
- class SimCppClassValue:
1753
+ class SimCppClassValue(SimStructValue):
1570
1754
  """
1571
1755
  A SimCppClass type paired with some real values
1572
1756
  """
1573
1757
 
1574
- def __init__(self, class_type, values):
1758
+ def __init__(self, class_type: SimCppClass, values):
1759
+ super().__init__(class_type, values)
1575
1760
  self._class = class_type
1576
- self._values = defaultdict(lambda: None, values or ())
1577
1761
 
1578
1762
  def __indented_repr__(self, indent=0):
1579
1763
  fields = []
@@ -1594,18 +1778,17 @@ class SimCppClassValue:
1594
1778
  def __getattr__(self, k):
1595
1779
  return self[k]
1596
1780
 
1597
- def __getitem__(self, k):
1598
- if type(k) is int:
1599
- k = self._class.fields[k]
1781
+ def __getitem__(self, k: int | str):
1782
+ if isinstance(k, int):
1783
+ k = list(self._class.fields.keys())[k]
1600
1784
  if k not in self._values:
1601
1785
  for f in self._class.fields:
1602
1786
  if isinstance(f, NamedTypeMixin) and f.name is None:
1603
1787
  try:
1604
- return f[k]
1788
+ return f[k] # type: ignore # lukas WHAT
1605
1789
  except KeyError:
1606
1790
  continue
1607
- else:
1608
- return self._values[k]
1791
+ return self._values[k]
1609
1792
 
1610
1793
  return self._values[k]
1611
1794
 
@@ -1624,6 +1807,12 @@ class SimTypeNumOffset(SimTypeNum):
1624
1807
  super().__init__(size, signed, label)
1625
1808
  self.offset = offset
1626
1809
 
1810
+ @overload
1811
+ def extract(self, state, addr, concrete: Literal[False] = ...) -> claripy.ast.BV: ...
1812
+
1813
+ @overload
1814
+ def extract(self, state, addr, concrete: Literal[True] = ...) -> int: ...
1815
+
1627
1816
  def extract(self, state: SimState, addr, concrete=False):
1628
1817
  if state.arch.memory_endness != Endness.LE:
1629
1818
  raise NotImplementedError("This has only been implemented and tested with Little Endian arches so far")
@@ -1659,7 +1848,7 @@ class SimTypeRef(SimType):
1659
1848
  self.original_type = original_type
1660
1849
 
1661
1850
  @property
1662
- def name(self) -> str:
1851
+ def name(self) -> str | None:
1663
1852
  return self.label
1664
1853
 
1665
1854
  def set_size(self, v: int):
@@ -1678,8 +1867,8 @@ class SimTypeRef(SimType):
1678
1867
  return f'SimTypeRef("{self.name}", {original_type_name})'
1679
1868
 
1680
1869
 
1681
- ALL_TYPES = {}
1682
- BASIC_TYPES = {
1870
+ ALL_TYPES: dict[str, SimType] = {}
1871
+ BASIC_TYPES: dict[str, SimType] = {
1683
1872
  "char": SimTypeChar(),
1684
1873
  "signed char": SimTypeChar(),
1685
1874
  "unsigned char": SimTypeChar(signed=False),
@@ -2756,6 +2945,8 @@ def define_struct(defn):
2756
2945
  >>> define_struct('struct abcd {int x; int y;}')
2757
2946
  """
2758
2947
  struct = parse_type(defn)
2948
+ if not isinstance(struct, SimStruct):
2949
+ raise AngrTypeError("Passed a non-struct type to define_struct")
2759
2950
  ALL_TYPES[struct.name] = struct
2760
2951
  ALL_TYPES["struct " + struct.name] = struct
2761
2952
  return struct
@@ -2840,6 +3031,7 @@ def parse_file(defn, preprocess=True, predefined_types: dict[Any, SimType] | Non
2840
3031
  if preprocess:
2841
3032
  defn = do_preprocess(defn)
2842
3033
 
3034
+ # pylint: disable=unexpected-keyword-arg
2843
3035
  node = pycparser.c_parser.CParser().parse(defn, scope_stack=_make_scope(predefined_types))
2844
3036
  if not isinstance(node, pycparser.c_ast.FileAST):
2845
3037
  raise ValueError("Something went horribly wrong using pycparser")
@@ -2859,12 +3051,14 @@ def parse_file(defn, preprocess=True, predefined_types: dict[Any, SimType] | Non
2859
3051
  out[piece.name] = ty
2860
3052
 
2861
3053
  # Don't forget to update typedef types
2862
- if (isinstance(ty, SimStruct) or isinstance(ty, SimUnion)) and ty.name != "<anon>":
3054
+ if isinstance(ty, (SimStruct, SimUnion)) and ty.name != "<anon>":
2863
3055
  for _, i in extra_types.items():
2864
- if type(i) is type(ty) and i.name == ty.name:
3056
+ if isinstance(i, type(ty)) and i.name == ty.name:
2865
3057
  if isinstance(ty, SimStruct):
3058
+ assert isinstance(i, SimStruct)
2866
3059
  i.fields = ty.fields
2867
3060
  else:
3061
+ assert isinstance(i, SimUnion)
2868
3062
  i.members = ty.members
2869
3063
 
2870
3064
  elif isinstance(piece, pycparser.c_ast.Typedef):
@@ -2877,7 +3071,7 @@ def parse_file(defn, preprocess=True, predefined_types: dict[Any, SimType] | Non
2877
3071
  _type_parser_singleton = None
2878
3072
 
2879
3073
 
2880
- def type_parser_singleton() -> pycparser.CParser | None:
3074
+ def type_parser_singleton() -> pycparser.CParser:
2881
3075
  global _type_parser_singleton # pylint:disable=global-statement
2882
3076
  if pycparser is not None:
2883
3077
  if _type_parser_singleton is None:
@@ -2916,6 +3110,7 @@ def parse_type_with_name(
2916
3110
  if preprocess:
2917
3111
  defn = re.sub(r"/\*.*?\*/", r"", defn)
2918
3112
 
3113
+ # pylint: disable=unexpected-keyword-arg
2919
3114
  node = type_parser_singleton().parse(text=defn, scope_stack=_make_scope(predefined_types))
2920
3115
  if not isinstance(node, pycparser.c_ast.Typename) and not isinstance(node, pycparser.c_ast.Decl):
2921
3116
  raise pycparser.c_parser.ParseError("Got an unexpected type out of pycparser")
@@ -2940,7 +3135,9 @@ def _accepts_scope_stack():
2940
3135
  setattr(pycparser.CParser, "parse", parse)
2941
3136
 
2942
3137
 
2943
- def _decl_to_type(decl, extra_types=None, bitsize=None, arch=None) -> SimType:
3138
+ def _decl_to_type(
3139
+ decl, extra_types: dict[str, SimType] | None = None, bitsize=None, arch: Arch | None = None
3140
+ ) -> SimType:
2944
3141
  if extra_types is None:
2945
3142
  extra_types = {}
2946
3143
 
@@ -2967,7 +3164,12 @@ def _decl_to_type(decl, extra_types=None, bitsize=None, arch=None) -> SimType:
2967
3164
  else None
2968
3165
  )
2969
3166
  # special handling: func(void) is func()
2970
- if len(argtyps) == 1 and isinstance(argtyps[0], SimTypeBottom) and arg_names[0] is None:
3167
+ if (
3168
+ len(argtyps) == 1
3169
+ and isinstance(argtyps[0], SimTypeBottom)
3170
+ and arg_names is not None
3171
+ and arg_names[0] is None
3172
+ ):
2971
3173
  argtyps = ()
2972
3174
  arg_names = None
2973
3175
  if argtyps and argtyps[-1] is ...:
@@ -2976,7 +3178,10 @@ def _decl_to_type(decl, extra_types=None, bitsize=None, arch=None) -> SimType:
2976
3178
  else:
2977
3179
  variadic = False
2978
3180
  r = SimTypeFunction(
2979
- argtyps, _decl_to_type(decl.type, extra_types, arch=arch), arg_names=arg_names, variadic=variadic
3181
+ cast(list[SimType], argtyps),
3182
+ _decl_to_type(decl.type, extra_types, arch=arch),
3183
+ arg_names=arg_names,
3184
+ variadic=variadic,
2980
3185
  )
2981
3186
  r._arch = arch
2982
3187
  return r
@@ -3025,9 +3230,11 @@ def _decl_to_type(decl, extra_types=None, bitsize=None, arch=None) -> SimType:
3025
3230
  from_global = False
3026
3231
  if struct is None:
3027
3232
  struct = ALL_TYPES.get(key, None)
3028
- from_global = True
3029
3233
  if struct is not None:
3234
+ from_global = True
3030
3235
  struct = struct.with_arch(arch)
3236
+ if struct is not None and not isinstance(struct, SimStruct):
3237
+ raise AngrTypeError("Provided a non-SimStruct value for a type that must be a struct")
3031
3238
 
3032
3239
  if struct is None:
3033
3240
  struct = SimStruct(fields, decl.name)
@@ -3055,12 +3262,14 @@ def _decl_to_type(decl, extra_types=None, bitsize=None, arch=None) -> SimType:
3055
3262
 
3056
3263
  if decl.name is not None:
3057
3264
  key = "union " + decl.name
3058
- if key in extra_types:
3059
- union = extra_types[key]
3060
- elif key in ALL_TYPES:
3061
- union = ALL_TYPES[key]
3062
- else:
3063
- union = None
3265
+ union = extra_types.get(key, None)
3266
+ from_global = False
3267
+ if union is None:
3268
+ if key in ALL_TYPES:
3269
+ union = ALL_TYPES[key]
3270
+ from_global = True
3271
+ if union is not None and not isinstance(union, SimUnion):
3272
+ raise AngrTypeError("Provided a non-SimUnion value for a type that must be a union")
3064
3273
 
3065
3274
  if union is None:
3066
3275
  union = SimUnion(fields, decl.name)
@@ -3068,7 +3277,11 @@ def _decl_to_type(decl, extra_types=None, bitsize=None, arch=None) -> SimType:
3068
3277
  elif not union.members:
3069
3278
  union.members = fields
3070
3279
  elif fields and union.members != fields:
3071
- raise ValueError("Redefining body of " + key)
3280
+ if from_global:
3281
+ union = SimStruct(fields, decl.name)
3282
+ union._arch = arch
3283
+ else:
3284
+ raise ValueError("Redefining body of " + key)
3072
3285
 
3073
3286
  extra_types[key] = union
3074
3287
  else:
@@ -3135,6 +3348,8 @@ def _parse_const(c, arch=None, extra_types=None):
3135
3348
 
3136
3349
 
3137
3350
  def _cpp_decl_to_type(decl: Any, extra_types: dict[str, SimType], opaque_classes=True):
3351
+ if CppHeaderParser is None:
3352
+ raise ImportError("Please install CppHeaderParser to parse C++ definitions")
3138
3353
  if isinstance(decl, CppHeaderParser.CppMethod):
3139
3354
  the_func = decl
3140
3355
  func_name = the_func["name"]
@@ -3154,7 +3369,7 @@ def _cpp_decl_to_type(decl: Any, extra_types: dict[str, SimType], opaque_classes
3154
3369
  arg_names.append(arg_name)
3155
3370
 
3156
3371
  args = tuple(args)
3157
- arg_names: tuple[str] = tuple(arg_names)
3372
+ arg_names_tuple: tuple[str, ...] = tuple(arg_names)
3158
3373
  # returns
3159
3374
  if not the_func["returns"].strip():
3160
3375
  returnty = SimTypeBottom()
@@ -3163,7 +3378,7 @@ def _cpp_decl_to_type(decl: Any, extra_types: dict[str, SimType], opaque_classes
3163
3378
  # other properties
3164
3379
  ctor = the_func["constructor"]
3165
3380
  dtor = the_func["destructor"]
3166
- func = SimTypeCppFunction(args, returnty, arg_names=arg_names, ctor=ctor, dtor=dtor)
3381
+ func = SimTypeCppFunction(args, returnty, arg_names=arg_names_tuple, ctor=ctor, dtor=dtor)
3167
3382
  return func
3168
3383
 
3169
3384
  elif isinstance(decl, str):
@@ -3202,9 +3417,9 @@ def _cpp_decl_to_type(decl: Any, extra_types: dict[str, SimType], opaque_classes
3202
3417
  else:
3203
3418
  raise TypeError("Unknown type '%s'" % " ".join(key))
3204
3419
 
3205
- if unqualified_name != decl:
3420
+ if unqualified_name != decl and isinstance(t, NamedTypeMixin):
3206
3421
  t = t.copy()
3207
- t.name = decl
3422
+ t.name = decl # pylint:disable=attribute-defined-outside-init
3208
3423
  return t
3209
3424
 
3210
3425
  raise NotImplementedError()
@@ -3216,6 +3431,7 @@ def normalize_cpp_function_name(name: str) -> str:
3216
3431
  while s != _s:
3217
3432
  _s = s if s is not None else _s
3218
3433
  s = re.sub(r"<[^<>]+>", "", _s)
3434
+ assert s is not None
3219
3435
 
3220
3436
  m = re.search(r"{([a-z\s]+)}", s)
3221
3437
  if m is not None:
@@ -3270,15 +3486,17 @@ def parse_cpp_file(cpp_decl, with_param_names: bool = False):
3270
3486
  func_decls: dict[str, SimTypeCppFunction] = {}
3271
3487
  for the_func in h.functions:
3272
3488
  # FIXME: We always assume that there is a "this" pointer but it is not the case for static methods.
3273
- proto: SimTypeCppFunction | None = _cpp_decl_to_type(the_func, {}, opaque_classes=True)
3489
+ proto = cast(Optional[SimTypeCppFunction], _cpp_decl_to_type(the_func, {}, opaque_classes=True))
3274
3490
  if proto is not None and the_func["class"]:
3275
- func_name = the_func["class"] + "::" + the_func["name"]
3276
- proto.args = (
3277
- SimTypePointer(pts_to=SimTypeBottom(label="void")),
3278
- ) + proto.args # pylint:disable=attribute-defined-outside-init
3491
+ func_name = cast(str, the_func["class"] + "::" + the_func["name"])
3492
+ proto.args = (SimTypePointer(pts_to=SimTypeBottom(label="void")),) + tuple(
3493
+ proto.args
3494
+ ) # pylint:disable=attribute-defined-outside-init
3279
3495
  proto.arg_names = ("this",) + proto.arg_names # pylint:disable=attribute-defined-outside-init
3496
+ elif proto is None:
3497
+ raise ValueError("proto is None but class is also None... not sure what this edge case means")
3280
3498
  else:
3281
- func_name = the_func["name"]
3499
+ func_name = cast(str, the_func["name"])
3282
3500
  func_decls[func_name] = proto
3283
3501
 
3284
3502
  return func_decls, {}
@@ -3296,7 +3514,7 @@ def dereference_simtype(
3296
3514
  if t.name in memo:
3297
3515
  return memo[t.name]
3298
3516
 
3299
- if type_collections:
3517
+ if type_collections and t.name is not None:
3300
3518
  for tc in type_collections:
3301
3519
  try:
3302
3520
  real_type = tc.get(t.name)
@@ -3334,7 +3552,7 @@ def dereference_simtype(
3334
3552
  dereference_simtype(t.returnty, type_collections, memo=memo) if t.returnty is not None else None
3335
3553
  )
3336
3554
  real_type = t.copy()
3337
- real_type.args = real_args
3555
+ real_type.args = tuple(real_args)
3338
3556
  real_type.returnty = real_return_type
3339
3557
  else:
3340
3558
  return t