diff options
author | Vitaly Buka <vitalybuka@chromium.org> | 2017-03-01 23:05:15 -0800 |
---|---|---|
committer | Vitaly Buka <vitalybuka@gmail.com> | 2017-03-06 00:37:12 -0800 |
commit | f62fe473bc890998ae8e2d16fdec7ce1292765c7 (patch) | |
tree | fef01b44dad57d7e27a79b304b3ec3da2c6e96e3 /src | |
parent | be54a445fdac155ef547b268b9c3854fe4b24c02 (diff) | |
download | libprotobuf-mutator-f62fe473bc890998ae8e2d16fdec7ce1292765c7.tar.gz |
Setup mutator with pointer to RandomEngine instead of seed.
Diffstat (limited to 'src')
-rw-r--r-- | src/libfuzzer/mutator.cc | 6 | ||||
-rw-r--r-- | src/libfuzzer/mutator.h | 2 | ||||
-rw-r--r-- | src/mutator.cc | 74 | ||||
-rw-r--r-- | src/mutator.h | 9 | ||||
-rw-r--r-- | src/mutator_test.cc | 12 | ||||
-rw-r--r-- | src/random.h | 26 |
6 files changed, 79 insertions, 50 deletions
diff --git a/src/libfuzzer/mutator.cc b/src/libfuzzer/mutator.cc index 3a4263b..193c3d4 100644 --- a/src/libfuzzer/mutator.cc +++ b/src/libfuzzer/mutator.cc @@ -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() @@ -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); diff --git a/src/libfuzzer/mutator.h b/src/libfuzzer/mutator.h index 0438dee..8e4d59e 100644 --- a/src/libfuzzer/mutator.h +++ b/src/libfuzzer/mutator.h @@ -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; diff --git a/src/mutator.cc b/src/mutator.cc index d3a71da..b42a24e 100644 --- a/src/mutator.cc +++ b/src/mutator.cc @@ -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; } @@ -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 @@ -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; @@ -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); } @@ -342,9 +342,9 @@ class DataSourceSampler { } ConstFieldInstance match_; - Mutator::RandomEngine* random_; + RandomEngine* random_; - WeightedReservoirSampler<ConstFieldInstance, Mutator::RandomEngine> sampler_; + WeightedReservoirSampler<ConstFieldInstance, RandomEngine> sampler_; }; } // namespace @@ -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()); @@ -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; @@ -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)); @@ -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)); } @@ -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)); @@ -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; } diff --git a/src/mutator.h b/src/mutator.h index 3f14d52..7331134 100644 --- a/src/mutator.h +++ b/src/mutator.h @@ -23,6 +23,7 @@ #include <string> #include "port/protobuf.h" +#include "src/random.h" namespace protobuf_mutator { @@ -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. @@ -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; @@ -84,7 +83,7 @@ class Mutator { protobuf::Message* message2); bool keep_initialized_ = true; - RandomEngine random_; + RandomEngine* random_; }; } // namespace protobuf_mutator diff --git a/src/mutator_test.cc b/src/mutator_test.cc index 9a8cd6c..d666032 100644 --- a/src/mutator_test.cc +++ b/src/mutator_test.cc @@ -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; } @@ -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); @@ -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", diff --git a/src/random.h b/src/random.h new file mode 100644 index 0000000..d4463d3 --- /dev/null +++ b/src/random.h @@ -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_ |