Skip to content

Commit

Permalink
Add Base.hash() method to sidestep python's hash()
Browse files Browse the repository at this point in the history
  • Loading branch information
twizmwazin committed Sep 20, 2024
1 parent 399602e commit 0d292af
Show file tree
Hide file tree
Showing 4 changed files with 21 additions and 13 deletions.
18 changes: 13 additions & 5 deletions claripy/ast/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -491,6 +491,14 @@ def _arg_serialize(arg: ArgType | Annotation) -> bytes:
def __hash__(self) -> int:
return self._hash

def hash(self) -> int:
"""Python's built in hash function is not collision resistant, so we use our own.
When you call `hash(ast)`, the value is derived from the claripy hash, but it gets
passed through python's non-resistent hash function first. This skips that step,
allowing the claripy hash to be used directly, eg as a cache key.
"""
return self._hash

@property
def cache_key(self: Self) -> ASTCacheKey[Self]:
"""
Expand Down Expand Up @@ -834,7 +842,7 @@ def children_asts(self) -> Iterator[Base]:
if isinstance(ast, Base):
ast_queue.append(iter(ast.args))

l.debug("Yielding AST %s with hash %s with %d children", ast, hash(ast), len(ast.args))
l.debug("Yielding AST %s with hash %s with %d children", ast, ast.hash(), len(ast.args))
yield ast

def leaf_asts(self) -> Iterator[Base]:
Expand Down Expand Up @@ -862,14 +870,14 @@ def is_leaf(self) -> bool:
"""
return self.depth == 1

def dbg_is_looped(self) -> bool:
l.debug("Checking AST with hash %s for looping", hash(self))
def dbg_is_looped(self) -> Base | bool: # TODO: this return type is bad
l.debug("Checking AST with hash %s for looping", self.hash())

seen = set()
for child_ast in self.children_asts():
if hash(child_ast) in seen:
if child_ast.hash() in seen:
return child_ast
seen.add(hash(child_ast))
seen.add(child_ast.hash())

return False

Expand Down
6 changes: 3 additions & 3 deletions claripy/frontend_mixins/constraint_deduplicator_mixin.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,14 @@ def simplify(self):
# we only add to the constraint hashes because we want to
# prevent previous (now simplified) constraints from
# being re-added
self._constraint_hashes.update(map(hash, added))
self._constraint_hashes.update(c.hash() for c in added)
return added

def _add(self, constraints, invalidate_cache=True):
filtered = tuple(c for c in constraints if hash(c) not in self._constraint_hashes)
filtered = tuple(c for c in constraints if c.hash() not in self._constraint_hashes)
if len(filtered) == 0:
return filtered

added = super()._add(filtered, invalidate_cache=invalidate_cache)
self._constraint_hashes.update(map(hash, added))
self._constraint_hashes.update(c.hash() for c in added)
return added
6 changes: 3 additions & 3 deletions tests/test_expression.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,9 +119,9 @@ def test_expression(self):
new_formula = old_formula.replace(old, new)
ooo_formula = new_formula.replace(new, ooo)

self.assertNotEqual(hash(old_formula), hash(new_formula))
self.assertNotEqual(hash(old_formula), hash(ooo_formula))
self.assertNotEqual(hash(new_formula), hash(ooo_formula))
self.assertNotEqual(old_formula.hash(), new_formula.hash())
self.assertNotEqual(old_formula.hash(), ooo_formula.hash())
self.assertNotEqual(new_formula.hash(), ooo_formula.hash())

self.assertEqual(old_formula.variables, frozenset(("old",)))
self.assertEqual(new_formula.variables, frozenset(("new",)))
Expand Down
4 changes: 2 additions & 2 deletions tests/test_serial.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,8 @@ def test_identity(self):
s.add(x == 3)
s.finalize()
ss = pickle.loads(pickle.dumps(s))
old_constraint_sets = [[hash(j) for j in k.constraints] for k in s._solver_list]
new_constraint_sets = [[hash(j) for j in k.constraints] for k in ss._solver_list]
old_constraint_sets = [[j.hash() for j in k.constraints] for k in s._solver_list]
new_constraint_sets = [[j.hash() for j in k.constraints] for k in ss._solver_list]
assert old_constraint_sets == new_constraint_sets
assert str(s.variables) == str(ss.variables)

Expand Down

0 comments on commit 0d292af

Please sign in to comment.