Skip to content

Commit

Permalink
Fuzzing fixes, and misc fixes in interp
Browse files Browse the repository at this point in the history
  • Loading branch information
d0c-s4vage committed Feb 21, 2020
1 parent e0c43e8 commit 55ccfba
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 40 deletions.
25 changes: 14 additions & 11 deletions pfp/fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ def __init__(self, stream=None, metadata_processor=None):

self._pfp__array_idx = None

self._pfp__snapshot_value = None
self._pfp__snapshot_stack = []

if stream is not None:
self._pfp__parse(stream, save_offset=True)
Expand Down Expand Up @@ -302,12 +302,13 @@ def _pfp__snapshot(self, recurse=True):
"""Save off the current value of the field
"""
if hasattr(self, "_pfp__value"):
self._pfp__snapshot_value = self._pfp__value
self._pfp__snapshot_stack.append(self._pfp__value)

def _pfp__restore_snapshot(self, recurse=True):
"""Restore a saved value snapshot
"""
self._pfp__value = self._pfp__snapshot_value
if hasattr(self, "_pfp__value"):
self._pfp__value = self._pfp__snapshot_stack.pop()

def _pfp__process_metadata(self):
"""Process the metadata once the entire struct has been
Expand Down Expand Up @@ -639,7 +640,11 @@ def __eq__(self, other):
# set: https://stackoverflow.com/a/1608907
def __hash__(self):
#return self._pfp__value.__hash__()
return self._pfp__build().__hash__()
res = self._pfp__build()
# bit fields return an array, not bytes
if isinstance(res, list):
return str(res).__hash__()
return res.__hash__()

def __repr__(self):
return "{}({!r})".format(self.__class__.__name__, self._pfp__value)
Expand Down Expand Up @@ -1083,10 +1088,7 @@ def _pfp__notify_update(self, child=None):
self._pfp__union_update_other_children = False

new_data = child._pfp__build()
try:
new_stream = bitwrap.BitwrappedStream(six.BytesIO(new_data))
except Exception as e:
__import__('pdb').set_trace()
new_stream = bitwrap.BitwrappedStream(six.BytesIO(new_data))
for other_child in self._pfp__children:
if other_child is child:
continue
Expand Down Expand Up @@ -2067,6 +2069,8 @@ def __init__(self, width, field_cls, stream=None, metadata_processor=None):
self.raw_data = None
self.implicit = False

self._pfp__snapshot_raw_stack = []

if stream is not None:
self._pfp__parse(stream, save_offset=True)
else:
Expand All @@ -2078,7 +2082,7 @@ def _pfp__snapshot(self, recurse=True):
"""Save off the current value of the field
"""
super(Array, self)._pfp__snapshot(recurse=recurse)
self.snapshot_raw_data = self.raw_data
self._pfp__snapshot_raw_stack.append(self.raw_data)

if recurse:
for item in self.items:
Expand All @@ -2088,7 +2092,7 @@ def _pfp__restore_snapshot(self, recurse=True):
"""Restore the snapshotted value without triggering any events
"""
super(Array, self)._pfp__restore_snapshot(recurse=recurse)
self.raw_data = self.snapshot_raw_data
self.raw_data = self._pfp__snapshot_raw_stack.pop()

if recurse:
for item in self.items:
Expand Down Expand Up @@ -2131,7 +2135,6 @@ def __eq__(self, other):
res = self._array_to_str()
return utils.binary(res) == utils.binary(PYSTR(other))
else:
__import__('pdb').set_trace()
raise Exception("TODO")

def __ne__(self, other):
Expand Down
58 changes: 29 additions & 29 deletions pfp/fuzz/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,35 +71,35 @@ def mutate(field, strat_name_or_cls, num=100, at_once=1, yield_changed=False):
# we don't need these ones anymore
del to_mutate

# save the current value of all subfields without
# triggering events
field._pfp__snapshot(recurse=True)

count = 0
for x in six.moves.range(num):

chosen_fields = set()
idx_pool = set([x for x in six.moves.xrange(len(with_strats))])

# modify `at_once` number of fields OR len(with_strats) number of fields,
# whichever is lower
for at_onces in six.moves.xrange(min(len(with_strats), at_once)):
# we'll never pull the same idx from idx_pool more than once
# since we're removing the idx after choosing it
rand_idx = rand.sample(idx_pool, 1)[0]
idx_pool.remove(rand_idx)

rand_field, field_strat = with_strats[rand_idx]
chosen_fields.add(rand_field)

field_strat.mutate(rand_field)

if yield_changed:
yield field, chosen_fields
else:
# yield back the original field
yield field

# restore the saved value of all subfields without
# save the current value of all subfields without
# triggering events
field._pfp__restore_snapshot(recurse=True)
field._pfp__snapshot(recurse=True)

try:
chosen_fields = set()
idx_pool = set([x for x in six.moves.xrange(len(with_strats))])

# modify `at_once` number of fields OR len(with_strats) number of fields,
# whichever is lower
for at_onces in six.moves.xrange(min(len(with_strats), at_once)):
# we'll never pull the same idx from idx_pool more than once
# since we're removing the idx after choosing it
rand_idx = rand.sample(idx_pool, 1)[0]
idx_pool.remove(rand_idx)

rand_field, field_strat = with_strats[rand_idx]
chosen_fields.add(rand_field)

field_strat.mutate(rand_field)

if yield_changed:
yield field, chosen_fields
else:
# yield back the original field
yield field
finally:
# restore the saved value of all subfields without
# triggering events
field._pfp__restore_snapshot(recurse=True)
2 changes: 2 additions & 0 deletions pfp/interp.py
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ def EnumDef(typedef_name, base_cls, enum_vals):
typedef_name,
(fields.Enum,),
{
"signed": base_cls.signed,
"width": base_cls.width,
"endian": base_cls.endian,
"format": base_cls.format,
Expand Down Expand Up @@ -2321,6 +2322,7 @@ def _handle_enum(self, node, scope, ctxt, stream):
curr_val._pfp__set_value(curr_val_parsed._pfp__value)
elif prev_val is not None:
curr_val = prev_val + 1
curr_val.signed = enum_cls.signed
curr_val._pfp__freeze()
enum_vals[enumerator.name] = curr_val
enum_vals[fields.PYVAL(curr_val)] = enumerator.name
Expand Down

0 comments on commit 55ccfba

Please sign in to comment.