class IntegerEdgeCases(Mutator):
"""
Generate integer edge cases. The numbers produced are distributed over a bell curve with
the edge case as the center.
"""
def __init__(self, obj, rand):
Mutator.__init__(self)
min_, max_ = self.get_limits(obj)
delta = max_ - min_
if 0xff >= delta >= 0:
# We are <= a single byte, set the space size of the range
self.space = delta + 1
self.full_space = self.space
def sequential():
return min_ + self.mutation_index
def random():
return rand.randint(min_, max_)
self.sequential_generator = sequential
self.random_generator = random
else:
# For more than a single byte, use edge case generator
self.generator = EdgeCaseGenerator(min_, max_)
self.space = len(self.generator.values)
self.full_space = self.generator.deviation
def sequential():
return self.generator.values[self.mutation_index]
def random():
return self.generator.gen_next(rand)
self.sequential_generator = sequential
self.random_generator = random
def get_limits(self, obj):
"""
Get the minimum and maximum values to generate edge cases for.
:param obj: The element this mutator is bound to.
:return: The minimum value of the number space, The maximum value of the number space.
"""
return 0, sys.maxsize
def perform_mutation(self, obj, value):
"""
Mutate the data element.
:param obj: The element to mutate.
:param value: The value to use when mutating.
:return:
"""
pass
def mutate(self, obj, gen):
value = gen()
self.perform_mutation(obj, value)
def sequential_mutation(self, obj):
self.mutate(obj, self.sequential_generator)
def random_mutation(self, obj):
self.mutate(obj, self.random_generator)
def get_count(self):
return self.space
class EdgeCaseGenerator:
"""
Computes the edge cases of numbers inside a given space.
"""
SCHAR_MIN = -128
SCHAR_MAX = 127
UCHAR_MAX = 255
CHAR_MIN = -128
CHAR_MAX = 127
SHRT_MIN = -32768
SHRT_MAX = 32767
USHRT_MAX = 65535
INT_MIN = -2147483647 - 1
INT_MAX = 2147483647
UINT_MAX = 4294967295
LONG_MIN = -2147483647 - 1
LONG_MAX = 2147483647
ULONG_MAX = 4294967295
LLONG_MIN = -9223372036854775807 - 1
LLONG_MAX = 9223372036854775807
ULLONG_MAX = 18446744073709551615
EDGES = [SCHAR_MIN, SCHAR_MAX, UCHAR_MAX, CHAR_MIN, CHAR_MAX, SHRT_MIN, SHRT_MAX, USHRT_MAX,
INT_MIN, INT_MAX, UINT_MAX, LONG_MIN, LONG_MAX, ULONG_MAX, LLONG_MIN, LLONG_MAX, ULLONG_MAX, 0]
# The maximum range to pick numbers around each edge
max_range = 0x4000
def __init__(self, min_num, max_num):
# The list of edge cases in the number space.
self.edges = self.EDGES
self.min_num = min_num
self.max_num = max_num
self.edges = [num for num in self.edges if max_num >= num >= min_num]
self.edges.append(min_num)
self.edges.append(max_num)
self.edges = list(set(self.edges))
self.edges.sort()
self.ranges = []
self.stddev = []
self.weights = []
# The sum of all the standard deviations at each edge case
self.deviation = 0
# Precomputed list of values for sequential mutator
self.values = []
# Compute range and standard deviation
for i in range(len(self.edges)):
edge = self.edges[i]
if edge <= 0 and edge != max_num:
# If edge <= 0, it is the distance to next edge
v = self.edges[i + 1] - edge
else:
# If edge > 0, it is the distance to the previous edge
v = edge - self.edges[i - 1]
# Cap the +/- range to a maximum
v = min(v, self.max_range)
self.ranges.append(v)
# We want the distribution to be a bell curve over
# 2x the range. This means stddev should be 2*range / 6
# since 99% of the numbers will be 3 stddev away from the mean
# Also, round up so if v is < 3, we get at least 1
sigma = float(v + 2) / 3
self.stddev.append(sigma)
# The 1st and last edge get 1/2 the weight since they are half curves
# We still store the full deviation but do an abs() of the next rng
if i == 0 or i == len(self.edges) - 1:
# Round up so we always have a valid stddev
sigma = (sigma + 1) / 2
self.deviation += sigma
# Weight each edge based on its range
sum_ = 0
for i in range(len(self.edges)):
weight = 1.0 - (1.0 * sum_ / self.deviation)
self.weights.append(weight)
s = self.stddev[i]
# The 1st and last edge get 1/2 the weight since they are half curves
# We still store the full deviation but do an abs() of the next rng
if i == 0 or i == len(self.edges) - 1:
s /= 2
sum_ += s
# Compute a list of +/- delta around each edge
for i in range(len(self.edges)):
if i != 0:
for j in range(-50, 0):
self.values.append(self.edges[i] + j)
self.values.append(self.edges[i])
if i != len(self.edges) - 1:
for j in range(1, 51):
self.values.append(self.edges[i] + j)
def range(self, edge_index):
return self.ranges[edge_index]
def gen_next(self, rand):
r = rand.random()
i = len(self.weights) - 1
while self.weights[i] <= r:
i -= 1
edge = self.edges[i]
sigma = self.stddev[i]
while True:
num = rand.gauss(0, 1)
if (num < 0 and edge == self.min_num) or (num > 0 and edge == self.max_num):
num *= -1
num = num * sigma
if edge == self.min_num:
num = math.floor(num)
elif edge == self.max_num:
num = math.ceil(num)
else:
num = round(num)
ret = edge + int(num)
if self.max_num >= ret >= self.min_num:
return int(ret)这是python版本代码,我要转为cpp版本,下面是已经完成的部分#ifndef MUTATOR_STRINGLENGTHEDGECASE_H
#define MUTATOR_STRINGLENGTHEDGECASE_H
#include <vector>
#include <memory>
#include "../utils.h"
#include "../../data_types/string_.h"
#include "../base.h"
class StringLengthEdgeCase : public IntegerEdgeCases {
public:
StringLengthEdgeCase(std::shared_ptr<StringBase> obj, std::mt19937 &rand);
std::pair<int64_t, int64_t> get_limits(std::shared_ptr<StringBase> obj) override;
std::vector<std::shared_ptr<StringBase>> mutated_elements;
void perform_mutation(std::shared_ptr<StringBase> obj, std::string value) override;
void sequential_mutation(std::shared_ptr<StringBase> obj) override;
void random_muatation(std::shared_ptr<StringBase> obj) override;
bool supported(std::shared_ptr<StringBase> obj) override;
private:
};
#endif //MUTATOR_STRINGLENGTHEDGECASE_H
#include "StringLengthEdgeCase.h"
#include <algorithm>
#include "../utils.h"
StringLengthEdgeCase::StringLengthEdgeCase(std::shared_ptr<StringBase> obj, std::mt19937 &rand) : IntegerEdgeCases(obj, rand) {}
std::pair<int64_t, int64_t> StringLengthEdgeCase::get_limits(std::shared_ptr<StringBase> obj) {
int64_t max_ = obj->mutator_config.max_output_size * 8;
int64_t size = obj->calculate_bit_size();
int64_t limit = std::max(max_, size);
limit = (limit + 7) / 8;
max_ = limit;
if (obj->max_length != -INT64_MAX) {
max_ = std::min(max_, obj->max_length);
}
int64_t min_ = 0;
if (obj->min_length != INT64_MAX) {
min_ = std::max(min_, obj->min_length);
}
return {min_, max_};
}
bool StringLengthEdgeCase::supported(std::shared_ptr<StringBase> obj) {
return std::dynamic_pointer_cast<String>(obj) != nullptr;
}
void StringLengthEdgeCase::perform_mutation(std::shared_ptr<StringBase> obj, std::string value) {
uint64_t valueLength = value.size();
obj->mutated_value = expand(obj->value, valueLength);
obj->mutated = true;
mutated_elements.push_back(obj);
}
void StringLengthEdgeCase: 使用的基类我已经完成,需要在当前代码中针对StringLengthEdgeCase重写一下sequential_mutation和random_muatation对面