#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
This module defines basic mutation strategies
"""
import six
import pfp.fuzz as fuzz
import pfp.fields as fields
import pfp.utils as utils
[docs]class BasicStrat(fuzz.StratGroup):
"""A basic strategy that has FieldStrats (field strategies) defined
for every field type. Nothing fancy, just basic.
"""
name = "basic"
[docs] class Int(fuzz.FieldStrat):
klass = [fields.IntBase]
def prob(self, field):
# generate the probabilities table
offset = 0
max_val = 1 << (field.width * 8)
if field.signed:
min_val = int(-max_val / 2)
max_val = int(max_val / 2) - 1
vals = [min_val, max_val, 0]
vals += [1 << (x * 8) for x in six.moves.range(field.width)]
vals += [-x for x in vals]
vals = sorted(set(vals))
vals = vals[:-1]
else:
min_val = 0
max_val -= 1
vals = [0]
vals += [
1 << (x * 4) for x in six.moves.range(field.width * 2)
]
vals.append((1 << (field.width * 8)) - 1)
# now add the +-1 values
new_vals = []
for val in vals[2:-1]:
new_vals.append(val - 1)
new_vals.append(val + 1)
vals += new_vals
pv = 1.0 / 3.0
res = [
(pv, vals),
(pv, six.moves.xrange(0, min(max_val, 0x100))),
(pv, {"min": min_val, "max": max_val}),
]
return res
[docs] class Float(fuzz.FieldStrat):
klass = fields.Float
prob = [(1.0, lambda: fuzz.rand.randfloat(-0x10000000, 0x10000000))]
[docs] class Double(fuzz.FieldStrat):
klass = fields.Double
prob = [(1.0, lambda: fuzz.rand.randfloat(-0x10000000, 0x10000000))]
[docs] class Enum(Int):
klass = fields.Enum
def prob(self, field):
# treat it the same as ints, with the addition of the actual (valid)
# enum values
res = super(BasicStrat.Enum, self).prob(field)
# add in the new enum values
prob_percent = 1.0 / float(len(res) + 1)
res = [(prob_percent, x[1]) for x in res]
res.append((prob_percent, list(filter(
lambda x: not isinstance(x, six.string_types),
field.enum_vals.keys(),
))))
return res
# class Array(fuzz.FieldStrat):
# klass = fields.Array
#
# # set the raw data to be a random string
# def next_val(self, field):
# rand_data_size = (
# fuzz.rand.randint(0, 0x100) * field.field_cls.width
# )
# return fuzz.rand.data(
# rand_data_size, [utils.binary(chr(x)) for x in six.moves.range(0x100)]
# )
[docs] class String(fuzz.FieldStrat):
klass = fields.String
[docs] def next_val(self, field):
rand_data_size = fuzz.rand.randint(0, 0x100)
res = fuzz.rand.data(
rand_data_size, [utils.binary(chr(x)) for x in six.moves.range(0x100)]
)
if fuzz.rand.maybe():
res += utils.binary("\x00")
return res