Source code for angr.storage.memory_mixins.multi_value_merger_mixin
from typing import Iterable, Tuple, Any, Callable, Optional
from . import MemoryMixin
[docs]class MultiValueMergerMixin(MemoryMixin):
[docs] def __init__(self, *args, element_limit=5, annotation_limit=256, top_func=None, phi_maker=None, **kwargs):
self._element_limit = element_limit
self._annotation_limit = annotation_limit
self._top_func: Callable = top_func
self._phi_maker: Optional[Callable] = phi_maker
super().__init__(*args, **kwargs)
def _merge_values(self, values: Iterable[Tuple[Any, Any]], merged_size: int, **kwargs):
values_set = {v for v, _ in values}
if self._phi_maker is not None:
phi_var = self._phi_maker(values_set)
if phi_var is not None:
return {phi_var}
# try to merge it in the traditional way
if len(values_set) > self._element_limit:
# strip annotations from each value and see how many raw values there are in total
# We have to use cache_key to determine uniqueness here, because if __hash__ collides,
# python implicitly calls __eq__ to determine if the two objects are actually the same
# and that just results in a new AST for a BV. Python then tries to convert that AST to a bool
# which fails with the safeguard in claripy.ast.bool.Bool.__bool__.
stripped_values_set = {v._apply_to_annotations(lambda alist: None).cache_key for v in values_set}
if len(stripped_values_set) > 1:
ret_val = self._top_func(merged_size * self.state.arch.byte_width)
else:
# Get the AST back from the cache_key
ret_val = next(iter(stripped_values_set)).ast
# migrate annotations
annotations = []
annotations_set = set()
for v in values_set:
for anno in v.annotations:
if anno not in annotations_set:
annotations.append(anno)
annotations_set.add(anno)
if annotations:
ret_val = ret_val.annotate(*annotations[: self._annotation_limit])
merged_val = {ret_val}
else:
merged_val = values_set
return merged_val
[docs] def copy(self, memo=None):
copied = super().copy(memo)
copied._element_limit = self._element_limit
copied._annotation_limit = self._annotation_limit
copied._top_func = self._top_func
copied._phi_maker = self._phi_maker
return copied