angr 9.2.96__py3-none-win_amd64.whl → 9.2.98__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 (52) hide show
  1. angr/__init__.py +1 -1
  2. angr/analyses/cfg/cfg_base.py +14 -1
  3. angr/analyses/cfg/indirect_jump_resolvers/propagator_utils.py +10 -6
  4. angr/analyses/complete_calling_conventions.py +27 -11
  5. angr/analyses/decompiler/ail_simplifier.py +20 -8
  6. angr/analyses/decompiler/condition_processor.py +2 -0
  7. angr/analyses/decompiler/optimization_passes/__init__.py +2 -0
  8. angr/analyses/decompiler/optimization_passes/inlined_string_transformation_simplifier.py +380 -0
  9. angr/analyses/decompiler/optimization_passes/x86_gcc_getpc_simplifier.py +4 -1
  10. angr/analyses/decompiler/peephole_optimizations/__init__.py +1 -0
  11. angr/analyses/decompiler/peephole_optimizations/inlined_strcpy.py +71 -3
  12. angr/analyses/decompiler/peephole_optimizations/inlined_wstrcpy.py +162 -0
  13. angr/analyses/decompiler/structured_codegen/__init__.py +1 -1
  14. angr/analyses/decompiler/structured_codegen/c.py +72 -99
  15. angr/analyses/decompiler/utils.py +5 -1
  16. angr/analyses/find_objects_static.py +15 -10
  17. angr/analyses/forward_analysis/forward_analysis.py +15 -1
  18. angr/analyses/propagator/engine_ail.py +2 -0
  19. angr/analyses/propagator/engine_vex.py +15 -0
  20. angr/analyses/propagator/propagator.py +6 -3
  21. angr/analyses/reaching_definitions/engine_vex.py +6 -0
  22. angr/analyses/reaching_definitions/rd_state.py +14 -1
  23. angr/analyses/reaching_definitions/reaching_definitions.py +19 -2
  24. angr/analyses/variable_recovery/engine_ail.py +6 -6
  25. angr/analyses/variable_recovery/engine_vex.py +6 -0
  26. angr/analyses/variable_recovery/irsb_scanner.py +12 -0
  27. angr/analyses/variable_recovery/variable_recovery_base.py +4 -1
  28. angr/engines/light/engine.py +134 -16
  29. angr/knowledge_plugins/functions/function.py +4 -0
  30. angr/knowledge_plugins/key_definitions/environment.py +11 -0
  31. angr/knowledge_plugins/key_definitions/live_definitions.py +41 -8
  32. angr/knowledge_plugins/key_definitions/uses.py +18 -4
  33. angr/knowledge_plugins/propagations/states.py +22 -3
  34. angr/knowledge_plugins/types.py +6 -0
  35. angr/knowledge_plugins/variables/variable_manager.py +31 -5
  36. angr/lib/angr_native.dll +0 -0
  37. angr/simos/simos.py +2 -0
  38. angr/storage/memory_mixins/__init__.py +3 -0
  39. angr/storage/memory_mixins/multi_value_merger_mixin.py +22 -11
  40. angr/storage/memory_mixins/paged_memory/paged_memory_mixin.py +20 -2
  41. angr/storage/memory_mixins/paged_memory/pages/list_page.py +20 -5
  42. angr/storage/memory_mixins/paged_memory/pages/mv_list_page.py +82 -44
  43. angr/storage/memory_mixins/simple_interface_mixin.py +4 -0
  44. angr/utils/cowdict.py +4 -2
  45. angr/utils/funcid.py +6 -0
  46. angr/utils/mp.py +1 -1
  47. {angr-9.2.96.dist-info → angr-9.2.98.dist-info}/METADATA +6 -6
  48. {angr-9.2.96.dist-info → angr-9.2.98.dist-info}/RECORD +52 -50
  49. {angr-9.2.96.dist-info → angr-9.2.98.dist-info}/LICENSE +0 -0
  50. {angr-9.2.96.dist-info → angr-9.2.98.dist-info}/WHEEL +0 -0
  51. {angr-9.2.96.dist-info → angr-9.2.98.dist-info}/entry_points.txt +0 -0
  52. {angr-9.2.96.dist-info → angr-9.2.98.dist-info}/top_level.txt +0 -0
@@ -49,11 +49,12 @@ class DefinitionAnnotation(Annotation):
49
49
  An annotation that attaches a `Definition` to an AST.
50
50
  """
51
51
 
52
- __slots__ = ("definition",)
52
+ __slots__ = ("definition", "_hash")
53
53
 
54
54
  def __init__(self, definition):
55
55
  super().__init__()
56
56
  self.definition = definition
57
+ self._hash = hash((DefinitionAnnotation, self.definition))
57
58
 
58
59
  @property
59
60
  def relocatable(self):
@@ -64,15 +65,11 @@ class DefinitionAnnotation(Annotation):
64
65
  return False
65
66
 
66
67
  def __hash__(self):
67
- return hash((self.definition, self.relocatable, self.eliminatable))
68
+ return self._hash
68
69
 
69
70
  def __eq__(self, other: "object"):
70
- if isinstance(other, DefinitionAnnotation):
71
- return (
72
- self.definition == other.definition
73
- and self.relocatable == other.relocatable
74
- and self.eliminatable == other.eliminatable
75
- )
71
+ if type(other) is DefinitionAnnotation:
72
+ return self.definition == other.definition
76
73
  else:
77
74
  return False
78
75
 
@@ -129,6 +126,7 @@ class LiveDefinitions:
129
126
  memory_uses=None,
130
127
  tmp_uses=None,
131
128
  other_uses=None,
129
+ element_limit=5,
132
130
  ):
133
131
  self.project: Optional["Project"] = None
134
132
  self.arch = arch
@@ -139,9 +137,11 @@ class LiveDefinitions:
139
137
  MultiValuedMemory(
140
138
  memory_id="reg",
141
139
  top_func=self.top,
140
+ is_top_func=self.is_top,
142
141
  skip_missing_values_during_merging=False,
143
142
  page_kwargs={"mo_cmp": self._mo_cmp},
144
143
  endness=self.arch.register_endness,
144
+ element_limit=element_limit,
145
145
  )
146
146
  if registers is None
147
147
  else registers
@@ -150,8 +150,10 @@ class LiveDefinitions:
150
150
  MultiValuedMemory(
151
151
  memory_id="mem",
152
152
  top_func=self.top,
153
+ is_top_func=self.is_top,
153
154
  skip_missing_values_during_merging=False,
154
155
  page_kwargs={"mo_cmp": self._mo_cmp},
156
+ element_limit=element_limit,
155
157
  )
156
158
  if stack is None
157
159
  else stack
@@ -160,8 +162,10 @@ class LiveDefinitions:
160
162
  MultiValuedMemory(
161
163
  memory_id="mem",
162
164
  top_func=self.top,
165
+ is_top_func=self.is_top,
163
166
  skip_missing_values_during_merging=False,
164
167
  page_kwargs={"mo_cmp": self._mo_cmp},
168
+ element_limit=element_limit,
165
169
  )
166
170
  if memory is None
167
171
  else memory
@@ -170,8 +174,10 @@ class LiveDefinitions:
170
174
  MultiValuedMemory(
171
175
  memory_id="mem",
172
176
  top_func=self.top,
177
+ is_top_func=self.is_top,
173
178
  skip_missing_values_during_merging=False,
174
179
  page_kwargs={"mo_cmp": self._mo_cmp},
180
+ element_limit=element_limit,
175
181
  )
176
182
  if heap is None
177
183
  else heap
@@ -464,6 +470,33 @@ class LiveDefinitions:
464
470
 
465
471
  return state, merge_occurred
466
472
 
473
+ def compare(self, other: "LiveDefinitions") -> bool:
474
+ r0 = self.registers.compare(other.registers)
475
+ if r0 is False:
476
+ return False
477
+ r1 = self.heap.compare(other.heap)
478
+ if r1 is False:
479
+ return False
480
+ r2 = self.memory.compare(other.memory)
481
+ if r2 is False:
482
+ return False
483
+ r3 = self.stack.compare(other.stack)
484
+ if r3 is False:
485
+ return False
486
+
487
+ r4 = True
488
+ for k in other.others:
489
+ if k in self.others:
490
+ thing = self.others[k].merge(other.others[k])
491
+ if thing != self.others[k]:
492
+ r4 = False
493
+ break
494
+ else:
495
+ r4 = False
496
+ break
497
+
498
+ return r0 and r1 and r2 and r3 and r4
499
+
467
500
  def kill_definitions(self, atom: Atom) -> None:
468
501
  """
469
502
  Overwrite existing definitions w.r.t 'atom' with a dummy definition instance. A dummy definition will not be
@@ -21,10 +21,14 @@ class Uses:
21
21
  uses_by_location: Optional[DefaultChainMapCOW] = None,
22
22
  ):
23
23
  self._uses_by_definition: DefaultChainMapCOW["Definition", Set[Tuple[CodeLocation, Optional[Any]]]] = (
24
- DefaultChainMapCOW(set, collapse_threshold=25) if uses_by_definition is None else uses_by_definition
24
+ DefaultChainMapCOW(default_factory=set, collapse_threshold=25)
25
+ if uses_by_definition is None
26
+ else uses_by_definition
25
27
  )
26
28
  self._uses_by_location: DefaultChainMapCOW[CodeLocation, Set[Tuple["Definition", Optional[Any]]]] = (
27
- DefaultChainMapCOW(set, collapse_threshold=25) if uses_by_location is None else uses_by_location
29
+ DefaultChainMapCOW(default_factory=set, collapse_threshold=25)
30
+ if uses_by_location is None
31
+ else uses_by_location
28
32
  )
29
33
 
30
34
  def add_use(self, definition: "Definition", codeloc: CodeLocation, expr: Optional[Any] = None):
@@ -35,7 +39,9 @@ class Uses:
35
39
  :param codeloc: The code location where the use occurs.
36
40
  :param expr: The expression that uses the specified definition at this location.
37
41
  """
42
+ self._uses_by_definition = self._uses_by_definition.clean()
38
43
  self._uses_by_definition[definition].add((codeloc, expr))
44
+ self._uses_by_location = self._uses_by_location.clean()
39
45
  self._uses_by_location[codeloc].add((definition, expr))
40
46
 
41
47
  def get_uses(self, definition: "Definition") -> Set[CodeLocation]:
@@ -65,6 +71,7 @@ class Uses:
65
71
  """
66
72
  if definition in self._uses_by_definition:
67
73
  if codeloc in self._uses_by_definition[definition]:
74
+ self._uses_by_definition = self._uses_by_definition.clean()
68
75
  if expr is None:
69
76
  for codeloc_, expr_ in list(self._uses_by_definition[definition]):
70
77
  if codeloc_ == codeloc:
@@ -73,6 +80,7 @@ class Uses:
73
80
  self._uses_by_definition[definition].remove((codeloc, expr))
74
81
 
75
82
  if codeloc in self._uses_by_location:
83
+ self._uses_by_location = self._uses_by_location.clean()
76
84
  for item in list(self._uses_by_location[codeloc]):
77
85
  if item[0] == definition:
78
86
  self._uses_by_location[codeloc].remove(item)
@@ -85,9 +93,11 @@ class Uses:
85
93
  :return: None
86
94
  """
87
95
  if definition in self._uses_by_definition:
96
+ self._uses_by_definition = self._uses_by_definition.clean()
88
97
  codeloc_and_ids = self._uses_by_definition[definition]
89
98
  del self._uses_by_definition[definition]
90
99
 
100
+ self._uses_by_location = self._uses_by_location.clean()
91
101
  for codeloc, _ in codeloc_and_ids:
92
102
  for item in list(self._uses_by_location[codeloc]):
93
103
  if item[0] == definition:
@@ -149,18 +159,22 @@ class Uses:
149
159
 
150
160
  for k, v in other._uses_by_definition.items():
151
161
  if k not in self._uses_by_definition:
162
+ self._uses_by_definition = self._uses_by_definition.clean()
152
163
  self._uses_by_definition[k] = v
153
164
  merge_occurred = True
154
165
  elif not v.issubset(self._uses_by_definition[k]):
155
166
  merge_occurred = True
156
- self._uses_by_definition[k] |= v
167
+ self._uses_by_definition = self._uses_by_definition.clean()
168
+ self._uses_by_definition[k] = self._uses_by_definition[k] | v
157
169
 
158
170
  for k, v in other._uses_by_location.items():
159
171
  if k not in self._uses_by_location:
172
+ self._uses_by_location = self._uses_by_location.clean()
160
173
  self._uses_by_location[k] = v
161
174
  merge_occurred = True
162
175
  elif not v.issubset(self._uses_by_location[k]):
163
176
  merge_occurred = True
164
- self._uses_by_location[k] |= v
177
+ self._uses_by_location = self._uses_by_location.clean()
178
+ self._uses_by_location[k] = self._uses_by_location[k] | v
165
179
 
166
180
  return merge_occurred
@@ -221,9 +221,10 @@ class PropagatorState:
221
221
  merge_occurred = True
222
222
  else:
223
223
  if PropagatorState.is_top(repl) or PropagatorState.is_top(replacements_0[loc][var]):
224
- t = PropagatorState.top(_get_repl_size(repl))
225
- replacements_0[loc][var] = t
226
- merge_occurred = True
224
+ if not PropagatorState.is_top(replacements_0[loc][var]):
225
+ t = PropagatorState.top(_get_repl_size(repl))
226
+ replacements_0[loc][var] = t
227
+ merge_occurred = True
227
228
  elif (
228
229
  isinstance(replacements_0[loc][var], claripy.ast.Base) or isinstance(repl, claripy.ast.Base)
229
230
  ) and replacements_0[loc][var] is not repl:
@@ -316,6 +317,12 @@ class RegisterAnnotation(claripy.Annotation):
316
317
  def relocatable(self) -> bool:
317
318
  return True
318
319
 
320
+ def __hash__(self):
321
+ return hash((RegisterAnnotation, self.offset, self.size))
322
+
323
+ def __eq__(self, other):
324
+ return type(other) is RegisterAnnotation and self.offset == other.offset and self.size == other.size
325
+
319
326
 
320
327
  class RegisterComparisonAnnotation(claripy.Annotation):
321
328
  """
@@ -336,6 +343,18 @@ class RegisterComparisonAnnotation(claripy.Annotation):
336
343
  def relocatable(self) -> bool:
337
344
  return True
338
345
 
346
+ def __hash__(self):
347
+ return hash((RegisterComparisonAnnotation, self.offset, self.size, self.cmp_op, self.value))
348
+
349
+ def __eq__(self, other):
350
+ return (
351
+ type(other) is RegisterAnnotation
352
+ and self.offset == other.offset
353
+ and self.size == other.size
354
+ and self.cmp_op == other.cmp_op
355
+ and self.value == other.value
356
+ )
357
+
339
358
 
340
359
  class PropagatorVEXState(PropagatorState):
341
360
  """
@@ -56,6 +56,12 @@ class TypesStore(KnowledgeBasePlugin, UserDict):
56
56
  yield from super().__iter__()
57
57
  yield from iter(ALL_TYPES)
58
58
 
59
+ def __getstate__(self):
60
+ return self.data # do not pickle self.kb
61
+
62
+ def __setstate__(self, state):
63
+ self.data = state
64
+
59
65
  def iter_own(self):
60
66
  """
61
67
  Iterate over all the names which are stored in this object - i.e. ``values()`` without ``ALL_TYPES``
@@ -122,7 +122,32 @@ class VariableManagerInternal(Serializable):
122
122
  self.__dict__.update(state)
123
123
 
124
124
  def __getstate__(self):
125
- d = dict(self.__dict__)
125
+ attributes = [
126
+ "func_addr",
127
+ "_variables",
128
+ "_global_region",
129
+ "_stack_region",
130
+ "_register_region",
131
+ "_live_variables",
132
+ "_variable_accesses",
133
+ "_insn_to_variable",
134
+ "_stmt_to_variable",
135
+ "_variable_to_stmt",
136
+ "_atom_to_variable",
137
+ "_ident_to_variable",
138
+ "_variable_counters",
139
+ "_unified_variables",
140
+ "_variables_to_unified_variables",
141
+ "_phi_variables",
142
+ "_variables_to_phivars",
143
+ "_phi_variables_by_block",
144
+ "types",
145
+ "variable_to_types",
146
+ "variables_with_manual_types",
147
+ "_variables_without_writes",
148
+ "ret_val_size",
149
+ ]
150
+ d = {k: getattr(self, k) for k in attributes}
126
151
  d["manager"] = None
127
152
  d["types"].kb = None
128
153
  return d
@@ -759,10 +784,11 @@ class VariableManagerInternal(Serializable):
759
784
  if variable in self._phi_variables:
760
785
  # a phi variable is definitely not an input variable
761
786
  continue
762
- accesses = self._variable_accesses[variable]
763
- if has_read_access(accesses):
764
- if not exclude_specials or not variable.category:
765
- input_variables.append(variable)
787
+ if variable in self._variable_accesses:
788
+ accesses = self._variable_accesses[variable]
789
+ if has_read_access(accesses):
790
+ if not exclude_specials or not variable.category:
791
+ input_variables.append(variable)
766
792
 
767
793
  return input_variables
768
794
 
angr/lib/angr_native.dll CHANGED
Binary file
angr/simos/simos.py CHANGED
@@ -277,6 +277,8 @@ class SimOS:
277
277
 
278
278
  if state.arch.name == "PPC64" and toc is not None:
279
279
  state.regs.r2 = toc
280
+ elif state.arch.name in ("MIPS32", "MIPS64"):
281
+ state.regs.t9 = addr
280
282
 
281
283
  return state
282
284
 
@@ -67,6 +67,9 @@ class MemoryMixin(SimStatePlugin):
67
67
  def merge(self, others, merge_conditions, common_ancestor=None) -> bool:
68
68
  pass
69
69
 
70
+ def compare(self, other) -> bool:
71
+ pass
72
+
70
73
  def widen(self, others):
71
74
  pass
72
75
 
@@ -1,13 +1,17 @@
1
+ # pylint:disable=missing-class-docstring
1
2
  from typing import Iterable, Tuple, Any, Callable, Optional
2
3
 
3
4
  from . import MemoryMixin
4
5
 
5
6
 
6
7
  class MultiValueMergerMixin(MemoryMixin):
7
- def __init__(self, *args, element_limit=5, annotation_limit=256, top_func=None, phi_maker=None, **kwargs):
8
+ def __init__(
9
+ self, *args, element_limit=5, annotation_limit=256, top_func=None, is_top_func=None, phi_maker=None, **kwargs
10
+ ):
8
11
  self._element_limit = element_limit
9
12
  self._annotation_limit = annotation_limit
10
13
  self._top_func: Callable = top_func
14
+ self._is_top_func: Callable = is_top_func
11
15
  self._phi_maker: Optional[Callable] = phi_maker
12
16
 
13
17
  super().__init__(*args, **kwargs)
@@ -20,18 +24,23 @@ class MultiValueMergerMixin(MemoryMixin):
20
24
  return {phi_var}
21
25
 
22
26
  # try to merge it in the traditional way
23
- if len(values_set) > self._element_limit:
24
- # strip annotations from each value and see how many raw values there are in total
25
- # We have to use cache_key to determine uniqueness here, because if __hash__ collides,
26
- # python implicitly calls __eq__ to determine if the two objects are actually the same
27
- # and that just results in a new AST for a BV. Python then tries to convert that AST to a bool
28
- # which fails with the safeguard in claripy.ast.bool.Bool.__bool__.
29
- stripped_values_set = {v._apply_to_annotations(lambda alist: None).cache_key for v in values_set}
30
- if len(stripped_values_set) > 1:
27
+ has_top = any(self._is_top_func(v) for v in values_set)
28
+ if has_top or len(values_set) > self._element_limit:
29
+ if has_top:
31
30
  ret_val = self._top_func(merged_size * self.state.arch.byte_width)
32
31
  else:
33
- # Get the AST back from the cache_key
34
- ret_val = next(iter(stripped_values_set)).ast
32
+ # strip annotations from each value and see how many raw values there are in total
33
+ # We have to use cache_key to determine uniqueness here, because if __hash__ collides,
34
+ # python implicitly calls __eq__ to determine if the two objects are actually the same
35
+ # and that just results in a new AST for a BV. Python then tries to convert that AST to a bool
36
+ # which fails with the safeguard in claripy.ast.bool.Bool.__bool__.
37
+ stripped_values_set = {v._apply_to_annotations(lambda alist: None).cache_key for v in values_set}
38
+ if len(stripped_values_set) > 1:
39
+ ret_val = self._top_func(merged_size * self.state.arch.byte_width)
40
+ else:
41
+ # Get the AST back from the cache_key
42
+ ret_val = next(iter(stripped_values_set)).ast
43
+
35
44
  # migrate annotations
36
45
  annotations = []
37
46
  annotations_set = set()
@@ -41,6 +50,7 @@ class MultiValueMergerMixin(MemoryMixin):
41
50
  annotations.append(anno)
42
51
  annotations_set.add(anno)
43
52
  if annotations:
53
+ annotations = sorted(annotations, key=str)
44
54
  ret_val = ret_val.annotate(*annotations[: self._annotation_limit])
45
55
  merged_val = {ret_val}
46
56
  else:
@@ -52,5 +62,6 @@ class MultiValueMergerMixin(MemoryMixin):
52
62
  copied._element_limit = self._element_limit
53
63
  copied._annotation_limit = self._annotation_limit
54
64
  copied._top_func = self._top_func
65
+ copied._is_top_func = self._is_top_func
55
66
  copied._phi_maker = self._phi_maker
56
67
  return copied
@@ -294,6 +294,24 @@ class PagedMemoryMixin(MemoryMixin):
294
294
 
295
295
  return bool(merged_bytes)
296
296
 
297
+ def compare(self, other: "PagedMemoryMixin") -> bool:
298
+ changed_pages_and_offsets: Dict[int, Optional[Set[int]]] = dict(self.changed_pages(other))
299
+
300
+ for page_no in sorted(changed_pages_and_offsets):
301
+ page = self._get_page(page_no, False)
302
+ page_addr = page_no * self.page_size
303
+ if page_no in other._pages:
304
+ r = page.compare(
305
+ other._pages[page_no],
306
+ page_addr=page_addr,
307
+ memory=self,
308
+ changed_offsets=changed_pages_and_offsets[page_no],
309
+ )
310
+ if r is False:
311
+ return False
312
+
313
+ return True
314
+
297
315
  def permissions(self, addr, permissions=None, **kwargs):
298
316
  if type(addr) is not int:
299
317
  raise TypeError("addr must be an int in paged memory")
@@ -643,10 +661,10 @@ class LabeledPagesMixin(PagedMemoryMixin):
643
661
  if endness is None:
644
662
  endness = self.endness
645
663
 
646
- if type(size) is not int:
664
+ if not isinstance(size, int):
647
665
  raise TypeError("Need size to be resolved to an int by this point")
648
666
 
649
- if type(addr) is not int:
667
+ if not isinstance(addr, int):
650
668
  raise TypeError("Need addr to be resolved to an int by this point")
651
669
 
652
670
  pageno, pageoff = self._divide_addr(addr)
@@ -2,6 +2,8 @@
2
2
  import logging
3
3
  from typing import Optional, List, Set, Tuple
4
4
 
5
+ import claripy
6
+
5
7
  from angr.utils.dynamic_dictlist import DynamicDictList
6
8
  from angr.storage.memory_object import SimMemoryObject, SimLabeledMemoryObject
7
9
  from . import PageBase
@@ -192,9 +194,14 @@ class ListPage(MemoryObjectMixin, PageBase):
192
194
  merged_offsets.add(b)
193
195
 
194
196
  else:
195
- # get the size that we can merge easily. This is the minimum of
196
- # the size of all memory objects and unallocated spaces.
197
- min_size = min([mo.length - (b + page_addr - mo.base) for mo, _ in memory_objects])
197
+ # get the size that we can merge easily. This is the minimum of the size of all memory objects and
198
+ # unallocated spaces.
199
+ min_size = None
200
+ mask = (1 << memory.state.arch.bits) - 1
201
+ for mo, _ in memory_objects:
202
+ mo_size = mo.length - ((b + page_addr - mo.base) & mask)
203
+ if min_size is None or mo_size < min_size:
204
+ min_size = mo_size
198
205
  for um, _ in unconstrained_in:
199
206
  for i in range(0, min_size):
200
207
  if um._contains(b + i, page_addr):
@@ -263,15 +270,23 @@ class ListPage(MemoryObjectMixin, PageBase):
263
270
  differences.add(c)
264
271
  else:
265
272
  if self.content[c] is None:
273
+ if self.sinkhole is None:
274
+ v = claripy.BVV(0, 8)
275
+ else:
276
+ v = (self.sinkhole.bytes_at(page_addr + c, 1),)
266
277
  self.content[c] = SimMemoryObject(
267
- self.sinkhole.bytes_at(page_addr + c, 1),
278
+ v,
268
279
  page_addr + c,
269
280
  byte_width=byte_width,
270
281
  endness="Iend_BE",
271
282
  )
272
283
  if other.content[c] is None:
284
+ if other.sinkhole is None:
285
+ v = claripy.BVV(0, 8)
286
+ else:
287
+ v = (other.sinkhole.bytes_at(page_addr + c, 1),)
273
288
  other.content[c] = SimMemoryObject(
274
- other.sinkhole.bytes_at(page_addr + c, 1),
289
+ v,
275
290
  page_addr + c,
276
291
  byte_width=byte_width,
277
292
  endness="Iend_BE",