Skip to content

Commit

Permalink
Setup mutator with pointer to RandomEngine instead of seed.
Browse files Browse the repository at this point in the history
  • Loading branch information
vitalybuka committed Mar 6, 2017
1 parent be54a44 commit f62fe47
Show file tree
Hide file tree
Showing 6 changed files with 79 additions and 50 deletions.
6 changes: 4 additions & 2 deletions src/libfuzzer/mutator.cc
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,8 @@ class BinaryOutputWriter : public OutputWriter {

size_t MutateMessage(unsigned int seed, const InputReader& input,
OutputWriter* output, Message* message) {
Mutator mutator(seed);
RandomEngine random(seed);
Mutator mutator(&random);
for (int i = 0; i < 100; ++i) {
input.Read(message);
mutator.Mutate(message, output->size() > input.size()
Expand All @@ -128,7 +129,8 @@ size_t CrossOverMessages(unsigned int seed, const InputReader& input1,
const InputReader& input2, OutputWriter* output,
protobuf::Message* message1,
protobuf::Message* message2) {
Mutator mutator(seed);
RandomEngine random(seed);
Mutator mutator(&random);
input2.Read(message2);
for (int i = 0; i < 100; ++i) {
input1.Read(message1);
Expand Down
2 changes: 1 addition & 1 deletion src/libfuzzer/mutator.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ namespace libfuzzer {
// implementation of this methods.
class Mutator : public protobuf_mutator::Mutator {
public:
explicit Mutator(uint32_t seed) : protobuf_mutator::Mutator(seed) {}
using protobuf_mutator::Mutator::Mutator;

protected:
int32_t MutateInt32(int32_t value) override;
Expand Down
74 changes: 37 additions & 37 deletions src/mutator.cc
Original file line number Diff line number Diff line change
Expand Up @@ -54,27 +54,27 @@ enum class Mutation {
};

// Return random integer from [0, count)
size_t GetRandomIndex(Mutator::RandomEngine* random, size_t count) {
size_t GetRandomIndex(RandomEngine* random, size_t count) {
assert(count > 0);
if (count == 1) return 0;
return std::uniform_int_distribution<size_t>(0, count - 1)(*random);
}

// Flips random bit in the buffer.
void FlipBit(size_t size, uint8_t* bytes, Mutator::RandomEngine* random) {
void FlipBit(size_t size, uint8_t* bytes, RandomEngine* random) {
size_t bit = GetRandomIndex(random, size * 8);
bytes[bit / 8] ^= (1u << (bit % 8));
}

// Flips random bit in the value.
template <class T>
T FlipBit(T value, Mutator::RandomEngine* random) {
T FlipBit(T value, RandomEngine* random) {
FlipBit(sizeof(value), reinterpret_cast<uint8_t*>(&value), random);
return value;
}

// Return true with probability about 1-of-n.
bool GetRandomBool(Mutator::RandomEngine* random, size_t n = 2) {
bool GetRandomBool(RandomEngine* random, size_t n = 2) {
return GetRandomIndex(random, n) == 0;
}

Expand Down Expand Up @@ -155,7 +155,7 @@ class IsEqualValueField : public FieldFunction<IsEqualValueField, bool> {
class MutationSampler {
public:
MutationSampler(bool keep_initialized, size_t size_increase_hint,
Mutator::RandomEngine* random, Message* message)
RandomEngine* random, Message* message)
: keep_initialized_(keep_initialized), random_(random), sampler_(random) {
if (size_increase_hint < kDeletionThreshold) {
// Avoid adding new field and prefer deleting fields if we getting close
Expand Down Expand Up @@ -270,7 +270,7 @@ class MutationSampler {
uint64_t add_weight_ = kMutateWeight / 10;
uint64_t delete_weight_ = kMutateWeight / 10;

Mutator::RandomEngine* random_;
RandomEngine* random_;

struct Result {
Result() = default;
Expand All @@ -279,14 +279,14 @@ class MutationSampler {
FieldInstance field;
Mutation mutation = Mutation::None;
};
WeightedReservoirSampler<Result, Mutator::RandomEngine> sampler_;
WeightedReservoirSampler<Result, RandomEngine> sampler_;
};

// Selects random field of compatible type to use for clone mutations.
class DataSourceSampler {
public:
DataSourceSampler(const ConstFieldInstance& match,
Mutator::RandomEngine* random, Message* message)
DataSourceSampler(const ConstFieldInstance& match, RandomEngine* random,
Message* message)
: match_(match), random_(random), sampler_(random) {
Sample(message);
}
Expand Down Expand Up @@ -342,9 +342,9 @@ class DataSourceSampler {
}

ConstFieldInstance match_;
Mutator::RandomEngine* random_;
RandomEngine* random_;

WeightedReservoirSampler<ConstFieldInstance, Mutator::RandomEngine> sampler_;
WeightedReservoirSampler<ConstFieldInstance, RandomEngine> sampler_;
};

} // namespace
Expand Down Expand Up @@ -435,19 +435,19 @@ struct CreateField : public FieldFunction<CreateField> {

} // namespace

Mutator::Mutator(uint32_t seed) : random_(seed) {}
Mutator::Mutator(RandomEngine* random) : random_(random) {}

void Mutator::Mutate(Message* message, size_t size_increase_hint) {
bool repeat;
do {
repeat = false;
MutationSampler mutation(keep_initialized_, size_increase_hint, &random_,
MutationSampler mutation(keep_initialized_, size_increase_hint, random_,
message);
switch (mutation.mutation()) {
case Mutation::None:
break;
case Mutation::Add:
if (GetRandomBool(&random_)) {
if (GetRandomBool(random_)) {
CreateField()(mutation.field(), this);
} else {
CreateDefaultField()(mutation.field());
Expand All @@ -460,7 +460,7 @@ void Mutator::Mutate(Message* message, size_t size_increase_hint) {
DeleteField()(mutation.field());
break;
case Mutation::Copy: {
DataSourceSampler source(mutation.field(), &random_, message);
DataSourceSampler source(mutation.field(), random_, message);
if (source.IsEmpty()) {
repeat = true;
break;
Expand Down Expand Up @@ -522,20 +522,20 @@ void Mutator::CrossOverImpl(const protobuf::Message& message1,

// Shuffle
for (int j = 0; j < field_size2; ++j) {
if (int k = GetRandomIndex(&random_, field_size2 - j)) {
if (int k = GetRandomIndex(random_, field_size2 - j)) {
reflection->SwapElements(message2, field, j, j + k);
}
}

int keep = GetRandomIndex(&random_, field_size2 + 1);
int keep = GetRandomIndex(random_, field_size2 + 1);

if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
int remove = field_size2 - keep;
// Cross some message to keep with messages to remove.
int cross = GetRandomIndex(&random_, std::min(keep, remove) + 1);
int cross = GetRandomIndex(random_, std::min(keep, remove) + 1);
for (int j = 0; j < cross; ++j) {
int k = GetRandomIndex(&random_, keep);
int r = keep + GetRandomIndex(&random_, remove);
int k = GetRandomIndex(random_, keep);
int r = keep + GetRandomIndex(random_, remove);
assert(k != r);
CrossOverImpl(reflection->GetRepeatedMessage(*message2, field, r),
reflection->MutableRepeatedMessage(message2, field, k));
Expand All @@ -548,10 +548,10 @@ void Mutator::CrossOverImpl(const protobuf::Message& message1,

} else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
if (!reflection->HasField(message1, field)) {
if (GetRandomBool(&random_))
if (GetRandomBool(random_))
DeleteField()(FieldInstance(message2, field));
} else if (!reflection->HasField(*message2, field)) {
if (GetRandomBool(&random_)) {
if (GetRandomBool(random_)) {
ConstFieldInstance source(&message1, field);
CopyField()(source, FieldInstance(message2, field));
}
Expand All @@ -560,7 +560,7 @@ void Mutator::CrossOverImpl(const protobuf::Message& message1,
reflection->MutableMessage(message2, field));
}
} else {
if (GetRandomBool(&random_)) {
if (GetRandomBool(random_)) {
if (reflection->HasField(message1, field)) {
ConstFieldInstance source(&message1, field);
CopyField()(source, FieldInstance(message2, field));
Expand Down Expand Up @@ -603,50 +603,50 @@ void Mutator::InitializeMessage(Message* message, size_t max_depth) {
}
}

int32_t Mutator::MutateInt32(int32_t value) { return FlipBit(value, &random_); }
int32_t Mutator::MutateInt32(int32_t value) { return FlipBit(value, random_); }

int64_t Mutator::MutateInt64(int64_t value) { return FlipBit(value, &random_); }
int64_t Mutator::MutateInt64(int64_t value) { return FlipBit(value, random_); }

uint32_t Mutator::MutateUInt32(uint32_t value) {
return FlipBit(value, &random_);
return FlipBit(value, random_);
}

uint64_t Mutator::MutateUInt64(uint64_t value) {
return FlipBit(value, &random_);
return FlipBit(value, random_);
}

float Mutator::MutateFloat(float value) { return FlipBit(value, &random_); }
float Mutator::MutateFloat(float value) { return FlipBit(value, random_); }

double Mutator::MutateDouble(double value) { return FlipBit(value, &random_); }
double Mutator::MutateDouble(double value) { return FlipBit(value, random_); }

bool Mutator::MutateBool(bool value) { return !value; }

size_t Mutator::MutateEnum(size_t index, size_t item_count) {
return (index + 1 + GetRandomIndex(&random_, item_count - 1)) % item_count;
return (index + 1 + GetRandomIndex(random_, item_count - 1)) % item_count;
}

std::string Mutator::MutateString(const std::string& value,
size_t size_increase_hint) {
std::string result = value;

while (!result.empty() && GetRandomBool(&random_)) {
result.erase(GetRandomIndex(&random_, result.size()), 1);
while (!result.empty() && GetRandomBool(random_)) {
result.erase(GetRandomIndex(random_, result.size()), 1);
}

while (result.size() < size_increase_hint && GetRandomBool(&random_)) {
size_t index = GetRandomIndex(&random_, result.size() + 1);
result.insert(result.begin() + index, GetRandomIndex(&random_, 1 << 8));
while (result.size() < size_increase_hint && GetRandomBool(random_)) {
size_t index = GetRandomIndex(random_, result.size() + 1);
result.insert(result.begin() + index, GetRandomIndex(random_, 1 << 8));
}

if (result != value) return result;

if (result.empty()) {
result.push_back(GetRandomIndex(&random_, 1 << 8));
result.push_back(GetRandomIndex(random_, 1 << 8));
return result;
}

if (!result.empty())
FlipBit(result.size(), reinterpret_cast<uint8_t*>(&result[0]), &random_);
FlipBit(result.size(), reinterpret_cast<uint8_t*>(&result[0]), random_);
return result;
}

Expand Down
9 changes: 4 additions & 5 deletions src/mutator.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include <string>

#include "port/protobuf.h"
#include "src/random.h"

namespace protobuf_mutator {

Expand All @@ -40,10 +41,8 @@ namespace protobuf_mutator {
// library like libFuzzer.
class Mutator {
public:
using RandomEngine = std::mt19937;

// seed: value to initialize random number generator.
explicit Mutator(uint32_t seed);
explicit Mutator(RandomEngine* random);
virtual ~Mutator() = default;

// message: message to mutate.
Expand Down Expand Up @@ -74,7 +73,7 @@ class Mutator {
// * Callbacks to recursive traversal.
// * Callbacks for particular proto level mutations.

RandomEngine* random() { return &random_; }
RandomEngine* random() { return random_; }

private:
friend class FieldMutator;
Expand All @@ -84,7 +83,7 @@ class Mutator {
protobuf::Message* message2);

bool keep_initialized_ = true;
RandomEngine random_;
RandomEngine* random_;
};

} // namespace protobuf_mutator
Expand Down
12 changes: 7 additions & 5 deletions src/mutator_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ const char kRepeatedNestedFields[] = R"(

class TestMutator : public Mutator {
public:
explicit TestMutator(bool keep_initialized) : Mutator(17) {
explicit TestMutator(bool keep_initialized) : Mutator(&random_), random_(17) {
keep_initialized_ = keep_initialized;
}

Expand All @@ -225,11 +225,14 @@ class TestMutator : public Mutator {
protobuf::Message* message2) {
CrossOverImpl(message1, message2);
}

private:
RandomEngine random_;
};

class ReducedTestMutator : public TestMutator {
public:
ReducedTestMutator() : TestMutator(false), random_(13) {
ReducedTestMutator() : TestMutator(false) {
for (float i = 1000; i > 0.1; i /= 7) {
values_.push_back(i);
values_.push_back(-i);
Expand All @@ -255,16 +258,15 @@ class ReducedTestMutator : public TestMutator {
std::string MutateString(const std::string& value,
size_t size_increase_hint) override {
return strings_[std::uniform_int_distribution<uint8_t>(
0, strings_.size() - 1)(random_)];
0, strings_.size() - 1)(*random())];
}

private:
float GetRandomValue() {
return values_[std::uniform_int_distribution<uint8_t>(
0, values_.size() - 1)(random_)];
0, values_.size() - 1)(*random())];
}

RandomEngine random_;
std::vector<float> values_;
std::vector<std::string> strings_ = {
"", "\001", "\000", "a", "b", "ab",
Expand Down
26 changes: 26 additions & 0 deletions src/random.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Copyright 2017 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef SRC_RANDOM_H_
#define SRC_RANDOM_H_

#include <random>

namespace protobuf_mutator {

using RandomEngine = std::mt19937;

} // namespace protobuf_mutator

#endif // SRC_RANDOM_H_

0 comments on commit f62fe47

Please sign in to comment.