Unify fuzzer random number generation into a single class

BUG=tint:1098

Change-Id: I84931804515487d931bbbb5f0d5239d03ca76dfc
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/63300
Auto-Submit: Ryan Harrison <rharrison@chromium.org>
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: Ryan Harrison <rharrison@chromium.org>
Reviewed-by: Alastair Donaldson <afdx@google.com>
This commit is contained in:
Ryan Harrison 2021-09-03 00:59:35 +00:00 committed by Tint LUCI CQ
parent 6a1eb45961
commit 5dc0ea7cce
26 changed files with 265 additions and 309 deletions

View File

@ -66,6 +66,8 @@ if (build_with_chromium) {
] ]
sources = [ sources = [
"random_generator.cc",
"random_generator.h",
"tint_common_fuzzer.cc", "tint_common_fuzzer.cc",
"tint_common_fuzzer.h", "tint_common_fuzzer.h",
] ]

View File

@ -17,6 +17,8 @@ function(add_tint_fuzzer NAME)
${NAME}.cc ${NAME}.cc
cli.cc cli.cc
cli.h cli.h
random_generator.cc
random_generator.h
tint_common_fuzzer.cc tint_common_fuzzer.cc
tint_common_fuzzer.h tint_common_fuzzer.h
tint_init_fuzzer.cc tint_init_fuzzer.cc

View File

@ -0,0 +1,89 @@
// Copyright 2021 The Tint Authors.
//
// 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.
#include "fuzzers/random_generator.h"
#include <algorithm>
#include <cassert>
#include <vector>
namespace tint {
namespace fuzzers {
namespace {
/// Generate integer from uniform distribution
/// @tparam I - integer type
/// @param engine - random number engine to use
/// @param lower - Lower bound of integer generated
/// @param upper - Upper bound of integer generated
/// @returns i, where lower <= i < upper
template <typename I>
I RandomUInt(std::mt19937* engine, I lower, I upper) {
assert(lower < upper && "|lower| must be stictly less than |upper|");
return std::uniform_int_distribution<I>(lower, upper - 1)(*engine);
}
} // namespace
RandomGenerator::RandomGenerator(uint32_t seed) : engine_(seed) {}
uint32_t RandomGenerator::GetUInt32(uint32_t lower, uint32_t upper) {
return RandomUInt(&engine_, lower, upper);
}
uint32_t RandomGenerator::GetUInt32(uint32_t bound) {
assert(bound > 0 && "|bound| must be greater than 0");
return RandomUInt(&engine_, 0u, bound);
}
uint64_t RandomGenerator::GetUInt64(uint64_t lower, uint64_t upper) {
return RandomUInt(&engine_, lower, upper);
}
uint64_t RandomGenerator::GetUInt64(uint64_t bound) {
assert(bound > 0 && "|bound| must be greater than 0");
return RandomUInt(&engine_, static_cast<uint64_t>(0), bound);
}
uint8_t RandomGenerator::GetByte() {
return std::independent_bits_engine<std::mt19937, 8, uint8_t>(engine_)();
}
uint32_t RandomGenerator::Get4Bytes() {
return std::independent_bits_engine<std::mt19937, 32, uint32_t>(engine_)();
}
std::vector<uint8_t> RandomGenerator::GetNBytes(size_t n) {
std::vector<uint8_t> result(n);
std::generate(
std::begin(result), std::end(result),
std::independent_bits_engine<std::mt19937, 8, uint8_t>(engine_));
return result;
}
bool RandomGenerator::GetBool() {
return RandomUInt(&engine_, 0u, 2u);
}
bool RandomGenerator::GetWeightedBool(uint32_t percentage) {
static const uint32_t kMaxPercentage = 100;
assert(percentage <= kMaxPercentage &&
"|percentage| needs to be within [0, 100]");
return RandomUInt(&engine_, 0u, kMaxPercentage) < percentage;
}
} // namespace fuzzers
} // namespace tint

View File

@ -0,0 +1,87 @@
// Copyright 2021 The Tint Authors.
//
// 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 FUZZERS_RANDOM_GENERATOR_H_
#define FUZZERS_RANDOM_GENERATOR_H_
#include <random>
#include <vector>
namespace tint {
namespace fuzzers {
/// Pseudo random generator utility class for fuzzing
class RandomGenerator {
public:
/// @brief Initializes the internal engine
/// @param seed - seed value passed to engine
explicit RandomGenerator(uint32_t seed);
~RandomGenerator() {}
/// Get uint32_t value from uniform distribution.
/// @param lower - lower bound of integer generated
/// @param upper - upper bound of integer generated
/// @returns i, where lower <= i < upper
uint32_t GetUInt32(uint32_t lower, uint32_t upper);
/// Get uint32_t value from uniform distribution.
/// @param bound - Upper bound of integer generated
/// @returns i, where 0 <= i < bound
uint32_t GetUInt32(uint32_t bound);
/// Get uint32_t value from uniform distribution.
/// @param lower - lower bound of integer generated
/// @param upper - upper bound of integer generated
/// @returns i, where lower <= i < upper
uint64_t GetUInt64(uint64_t lower, uint64_t upper);
/// Get uint64_t value from uniform distribution.
/// @param bound - Upper bound of integer generated
/// @returns i, where 0 <= i < bound
uint64_t GetUInt64(uint64_t bound);
/// Get 1 byte of pseudo-random data
/// Should be more efficient then calling GetNBytes(1);
/// @returns 1-byte of random data
uint8_t GetByte();
/// Get 4 bytes of pseudo-random data
/// Should be more efficient then calling GetNBytes(4);
/// @returns 4-bytes of random data
uint32_t Get4Bytes();
/// Get N bytes of pseudo-random data
/// @param n - number of bytes of data to generate
/// @returns |N|-bytes of random data as vector
std::vector<uint8_t> GetNBytes(size_t n);
/// Get random bool with even odds
/// @returns true 50% of the time and false %50 of time.
bool GetBool();
/// Get random bool with weighted odds
/// @param percentage - likelihood of true being returned
/// @returns true |percentage|% of the time, and false (100 - |percentage|)%
/// of the time.
bool GetWeightedBool(uint32_t percentage);
private:
std::mt19937 engine_;
}; // class RandomGenerator
} // namespace fuzzers
} // namespace tint
#endif // FUZZERS_RANDOM_GENERATOR_H_

View File

@ -42,8 +42,6 @@ if (build_with_chromium) {
"cli.cc", "cli.cc",
"cli.h", "cli.h",
"fuzzer.cc", "fuzzer.cc",
"mt_rng.cc",
"mt_rng.h",
"mutation.cc", "mutation.cc",
"mutation.h", "mutation.h",
"mutation_finder.cc", "mutation_finder.cc",
@ -60,8 +58,6 @@ if (build_with_chromium) {
"probability_context.cc", "probability_context.cc",
"probability_context.h", "probability_context.h",
"protobufs/tint_ast_fuzzer.h", "protobufs/tint_ast_fuzzer.h",
"random_number_generator.cc",
"random_number_generator.h",
"util.h", "util.h",
] ]
} }

View File

@ -35,7 +35,7 @@ add_custom_command(
COMMENT "Generate protobuf sources from proto definition file.") COMMENT "Generate protobuf sources from proto definition file.")
set(LIBTINT_AST_FUZZER_SOURCES set(LIBTINT_AST_FUZZER_SOURCES
mt_rng.h ../random_generator.h
mutation.h mutation.h
mutation_finder.h mutation_finder.h
mutation_finders/replace_identifiers.h mutation_finders/replace_identifiers.h
@ -44,12 +44,11 @@ set(LIBTINT_AST_FUZZER_SOURCES
node_id_map.h node_id_map.h
probability_context.h probability_context.h
protobufs/tint_ast_fuzzer.h protobufs/tint_ast_fuzzer.h
random_number_generator.h
util.h util.h
${CMAKE_CURRENT_BINARY_DIR}/protobufs/tint_ast_fuzzer.pb.h) ${CMAKE_CURRENT_BINARY_DIR}/protobufs/tint_ast_fuzzer.pb.h)
set(LIBTINT_AST_FUZZER_SOURCES ${LIBTINT_AST_FUZZER_SOURCES} set(LIBTINT_AST_FUZZER_SOURCES ${LIBTINT_AST_FUZZER_SOURCES}
mt_rng.cc ../random_generator.cc
mutation.cc mutation.cc
mutation_finder.cc mutation_finder.cc
mutation_finders/replace_identifiers.cc mutation_finders/replace_identifiers.cc
@ -57,7 +56,6 @@ set(LIBTINT_AST_FUZZER_SOURCES ${LIBTINT_AST_FUZZER_SOURCES}
mutator.cc mutator.cc
node_id_map.cc node_id_map.cc
probability_context.cc probability_context.cc
random_number_generator.cc
${CMAKE_CURRENT_BINARY_DIR}/protobufs/tint_ast_fuzzer.pb.cc) ${CMAKE_CURRENT_BINARY_DIR}/protobufs/tint_ast_fuzzer.pb.cc)
set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/protobufs/tint_ast_fuzzer.pb.cc PROPERTIES COMPILE_FLAGS -w) set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/protobufs/tint_ast_fuzzer.pb.cc PROPERTIES COMPILE_FLAGS -w)

View File

@ -15,8 +15,8 @@
#include <cstddef> #include <cstddef>
#include <cstdint> #include <cstdint>
#include "fuzzers/random_generator.h"
#include "fuzzers/tint_ast_fuzzer/cli.h" #include "fuzzers/tint_ast_fuzzer/cli.h"
#include "fuzzers/tint_ast_fuzzer/mt_rng.h"
#include "fuzzers/tint_ast_fuzzer/mutator.h" #include "fuzzers/tint_ast_fuzzer/mutator.h"
#include "fuzzers/tint_ast_fuzzer/override_cli_params.h" #include "fuzzers/tint_ast_fuzzer/override_cli_params.h"
#include "fuzzers/tint_common_fuzzer.h" #include "fuzzers/tint_common_fuzzer.h"
@ -54,8 +54,8 @@ extern "C" size_t LLVMFuzzerCustomMutator(uint8_t* data,
} }
// Run the mutator. // Run the mutator.
MtRng mt_rng(seed); RandomGenerator generator(seed);
ProbabilityContext probability_context(&mt_rng); ProbabilityContext probability_context(&generator);
program = Mutate(std::move(program), &probability_context, program = Mutate(std::move(program), &probability_context,
cli_params.enable_all_mutations, cli_params.enable_all_mutations,
cli_params.mutation_batch_size, nullptr); cli_params.mutation_batch_size, nullptr);

View File

@ -1,44 +0,0 @@
// Copyright 2021 The Tint Authors.
//
// 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.
#include "fuzzers/tint_ast_fuzzer/mt_rng.h"
#include <cassert>
namespace tint {
namespace fuzzers {
namespace ast_fuzzer {
namespace {
template <typename T>
T RandomUInt(std::mt19937* rng, T bound) {
assert(bound > 0 && "`bound` must be positive");
return std::uniform_int_distribution<T>(0, bound - 1)(*rng);
}
} // namespace
MtRng::MtRng(uint32_t seed) : rng_(seed) {}
uint32_t MtRng::RandomUint32(uint32_t bound) {
return RandomUInt(&rng_, bound);
}
uint64_t MtRng::RandomUint64(uint64_t bound) {
return RandomUInt(&rng_, bound);
}
} // namespace ast_fuzzer
} // namespace fuzzers
} // namespace tint

View File

@ -1,45 +0,0 @@
// Copyright 2021 The Tint Authors.
//
// 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 FUZZERS_TINT_AST_FUZZER_MT_RNG_H_
#define FUZZERS_TINT_AST_FUZZER_MT_RNG_H_
#include <random>
#include "fuzzers/tint_ast_fuzzer/random_number_generator.h"
namespace tint {
namespace fuzzers {
namespace ast_fuzzer {
/// The random number generator that uses STL's Mersenne Twister (std::mt19937)
/// under the hood.
class MtRng : public RandomNumberGenerator {
public:
/// @brief Initializes this RNG with some `seed`.
/// @param seed - passed down to the `std::mt19937`.
explicit MtRng(uint32_t seed);
uint32_t RandomUint32(uint32_t bound) override;
uint64_t RandomUint64(uint64_t bound) override;
private:
std::mt19937 rng_;
};
} // namespace ast_fuzzer
} // namespace fuzzers
} // namespace tint
#endif // FUZZERS_TINT_AST_FUZZER_MT_RNG_H_

View File

@ -16,7 +16,6 @@
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "fuzzers/tint_ast_fuzzer/mt_rng.h"
#include "fuzzers/tint_ast_fuzzer/mutations/replace_identifier.h" #include "fuzzers/tint_ast_fuzzer/mutations/replace_identifier.h"
#include "fuzzers/tint_ast_fuzzer/mutator.h" #include "fuzzers/tint_ast_fuzzer/mutator.h"
#include "fuzzers/tint_ast_fuzzer/probability_context.h" #include "fuzzers/tint_ast_fuzzer/probability_context.h"

View File

@ -20,7 +20,6 @@
#include "fuzzers/tint_ast_fuzzer/node_id_map.h" #include "fuzzers/tint_ast_fuzzer/node_id_map.h"
#include "fuzzers/tint_ast_fuzzer/probability_context.h" #include "fuzzers/tint_ast_fuzzer/probability_context.h"
#include "fuzzers/tint_ast_fuzzer/protobufs/tint_ast_fuzzer.h" #include "fuzzers/tint_ast_fuzzer/protobufs/tint_ast_fuzzer.h"
#include "fuzzers/tint_ast_fuzzer/random_number_generator.h"
#include "src/program.h" #include "src/program.h"

View File

@ -14,6 +14,8 @@
#include "fuzzers/tint_ast_fuzzer/probability_context.h" #include "fuzzers/tint_ast_fuzzer/probability_context.h"
#include <cassert>
namespace tint { namespace tint {
namespace fuzzers { namespace fuzzers {
namespace ast_fuzzer { namespace ast_fuzzer {
@ -23,15 +25,18 @@ const std::pair<uint32_t, uint32_t> kChanceOfReplacingIdentifiers = {30, 70};
} // namespace } // namespace
ProbabilityContext::ProbabilityContext(RandomNumberGenerator* rng) ProbabilityContext::ProbabilityContext(RandomGenerator* generator)
: rng_(rng), : generator_(generator),
chance_of_replacing_identifiers_( chance_of_replacing_identifiers_(
RandomFromRange(kChanceOfReplacingIdentifiers)) {} RandomFromRange(kChanceOfReplacingIdentifiers)) {
assert(generator != nullptr && "generator must not be nullptr");
}
uint32_t ProbabilityContext::RandomFromRange( uint32_t ProbabilityContext::RandomFromRange(
std::pair<uint32_t, uint32_t> range) { std::pair<uint32_t, uint32_t> range) {
assert(range.first <= range.second && "Range must be non-decreasing"); assert(range.first <= range.second && "Range must be non-decreasing");
return range.first + rng_->RandomUint32(range.second - range.first + 1); return generator_->GetUInt32(
range.first, range.second + 1); // + 1 need since range is inclusive.
} }
} // namespace ast_fuzzer } // namespace ast_fuzzer

View File

@ -18,7 +18,7 @@
#include <utility> #include <utility>
#include <vector> #include <vector>
#include "fuzzers/tint_ast_fuzzer/random_number_generator.h" #include "fuzzers/random_generator.h"
namespace tint { namespace tint {
namespace fuzzers { namespace fuzzers {
@ -29,16 +29,21 @@ namespace ast_fuzzer {
class ProbabilityContext { class ProbabilityContext {
public: public:
/// Initializes this instance with a random number generator. /// Initializes this instance with a random number generator.
/// @param rng - may not be a `nullptr`. Must remain in scope as long as this /// @param generator - must not be a `nullptr`. Must remain in scope as long
/// as this
/// instance exists. /// instance exists.
explicit ProbabilityContext(RandomNumberGenerator* rng); explicit ProbabilityContext(RandomGenerator* generator);
/// @copydoc RandomNumberGenerator::RandomBool /// Get random bool with even odds
bool RandomBool() { return rng_->RandomBool(); } /// @returns true 50% of the time and false %50 of time.
bool RandomBool() { return generator_->GetBool(); }
/// @copydoc RandomNumberGenerator::ChoosePercentage /// Get random bool with weighted odds
/// @param percentage - likelihood of true being returned
/// @returns true |percentage|% of the time, and false (100 - |percentage|)%
/// of the time.
bool ChoosePercentage(uint32_t percentage) { bool ChoosePercentage(uint32_t percentage) {
return rng_->ChoosePercentage(percentage); return generator_->GetWeightedBool(percentage);
} }
/// Returns a random value in the range `[0; arr.size())`. /// Returns a random value in the range `[0; arr.size())`.
@ -47,7 +52,7 @@ class ProbabilityContext {
/// @return the random index in the `arr`. /// @return the random index in the `arr`.
template <typename T> template <typename T>
size_t GetRandomIndex(const std::vector<T>& arr) { size_t GetRandomIndex(const std::vector<T>& arr) {
return static_cast<size_t>(rng_->RandomUint64(arr.size())); return static_cast<size_t>(generator_->GetUInt64(arr.size()));
} }
/// @return the probability of replacing some identifier with some other one. /// @return the probability of replacing some identifier with some other one.
@ -60,7 +65,7 @@ class ProbabilityContext {
/// @return an random number in the range `[a; b]`. /// @return an random number in the range `[a; b]`.
uint32_t RandomFromRange(std::pair<uint32_t, uint32_t> range); uint32_t RandomFromRange(std::pair<uint32_t, uint32_t> range);
RandomNumberGenerator* rng_; RandomGenerator* generator_;
uint32_t chance_of_replacing_identifiers_; uint32_t chance_of_replacing_identifiers_;
}; };

View File

@ -1,37 +0,0 @@
// Copyright 2021 The Tint Authors.
//
// 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.
#include "fuzzers/tint_ast_fuzzer/random_number_generator.h"
namespace tint {
namespace fuzzers {
namespace ast_fuzzer {
RandomNumberGenerator::~RandomNumberGenerator() = default;
bool RandomNumberGenerator::RandomBool() {
return RandomUint32(2);
}
bool RandomNumberGenerator::ChoosePercentage(uint32_t percentage) {
assert(percentage <= 100 && "|percentage| is invalid");
// 100 is used as a bound instead of 101 because otherwise it would be
// possible to return `false` when `percentage == 100` holds. This would
// happen when the result of `RandomUint32` is 100 as well.
return RandomUint32(100) < percentage;
}
} // namespace ast_fuzzer
} // namespace fuzzers
} // namespace tint

View File

@ -1,57 +0,0 @@
// Copyright 2021 The Tint Authors.
//
// 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 FUZZERS_TINT_AST_FUZZER_RANDOM_NUMBER_GENERATOR_H_
#define FUZZERS_TINT_AST_FUZZER_RANDOM_NUMBER_GENERATOR_H_
#include <cassert>
#include <cstdint>
#include <vector>
namespace tint {
namespace fuzzers {
namespace ast_fuzzer {
/// Abstracts away the underlying algorithm that is used to generate random
/// numbers.
class RandomNumberGenerator {
public:
/// Virtual destructor.
virtual ~RandomNumberGenerator();
/// @brief Compute a random `uint32_t` value in the range `[0; bound)`.
/// @param bound - the upper exclusive bound for the computed integer
/// (must be positive).
/// @return the random number.
virtual uint32_t RandomUint32(uint32_t bound) = 0;
/// @brief Compute a random `uint64_t` value in the range `[0; bound)`.
/// @param bound - the upper exclusive bound for the computed integer
/// (must be positive).
/// @return the random number.
virtual uint64_t RandomUint64(uint64_t bound) = 0;
/// @return a randomly generated boolean value.
bool RandomBool();
/// @param percentage - must be in the range `[0; 100]`.
/// @return `true` with `percentage` probability.
bool ChoosePercentage(uint32_t percentage);
};
} // namespace ast_fuzzer
} // namespace fuzzers
} // namespace tint
#endif // FUZZERS_TINT_AST_FUZZER_RANDOM_NUMBER_GENERATOR_H_

View File

@ -21,7 +21,8 @@ function(add_tint_regex_fuzzer NAME)
endfunction() endfunction()
set(LIBTINT_REGEX_FUZZER_SOURCES set(LIBTINT_REGEX_FUZZER_SOURCES
util.h ../random_generator.cc
../random_generator.h
wgsl_mutator.cc wgsl_mutator.cc
wgsl_mutator.h) wgsl_mutator.h)

View File

@ -16,12 +16,11 @@
#include <cstddef> #include <cstddef>
#include <cstdint> #include <cstdint>
#include "fuzzers/random_generator.h"
#include "fuzzers/tint_common_fuzzer.h" #include "fuzzers/tint_common_fuzzer.h"
#include "fuzzers/tint_regex_fuzzer/cli.h" #include "fuzzers/tint_regex_fuzzer/cli.h"
#include "fuzzers/tint_regex_fuzzer/override_cli_params.h" #include "fuzzers/tint_regex_fuzzer/override_cli_params.h"
#include "fuzzers/tint_regex_fuzzer/util.h"
#include "fuzzers/tint_regex_fuzzer/wgsl_mutator.h" #include "fuzzers/tint_regex_fuzzer/wgsl_mutator.h"
#include "src/reader/wgsl/parser.h" #include "src/reader/wgsl/parser.h"
#include "src/writer/wgsl/generator.h" #include "src/writer/wgsl/generator.h"
@ -57,13 +56,13 @@ extern "C" size_t LLVMFuzzerCustomMutator(uint8_t* data,
unsigned seed) { unsigned seed) {
std::string wgsl_code(data, data + size); std::string wgsl_code(data, data + size);
const std::vector<std::string> delimiters{";"}; const std::vector<std::string> delimiters{";"};
std::mt19937 generator(seed); RandomGenerator generator(seed);
std::string delimiter = std::string delimiter =
delimiters[GetRandomIntFromRange(0, delimiters.size() - 1, generator)]; delimiters[generator.GetUInt64(delimiters.size() - 1u)];
MutationKind mutation_kind = static_cast<MutationKind>(GetRandomIntFromRange( MutationKind mutation_kind = static_cast<MutationKind>(generator.GetUInt64(
0, static_cast<size_t>(MutationKind::kNumMutationKinds) - 1, generator)); static_cast<size_t>(MutationKind::kNumMutationKinds) - 1u));
switch (mutation_kind) { switch (mutation_kind) {
case MutationKind::kSwapIntervals: case MutationKind::kSwapIntervals:

View File

@ -1,33 +0,0 @@
// Copyright 2021 The Tint Authors.
//
// 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 FUZZERS_TINT_REGEX_FUZZER_UTIL_H_
#define FUZZERS_TINT_REGEX_FUZZER_UTIL_H_
#include <random>
namespace tint {
namespace fuzzers {
namespace regex_fuzzer {
inline size_t GetRandomIntFromRange(size_t lower_bound,
size_t upper_bound,
std::mt19937& generator) {
std::uniform_int_distribution<size_t> dist(lower_bound, upper_bound);
return dist(generator);
}
} // namespace regex_fuzzer
} // namespace fuzzers
} // namespace tint
#endif // FUZZERS_TINT_REGEX_FUZZER_UTIL_H_

View File

@ -17,13 +17,12 @@
#include <cassert> #include <cassert>
#include <cstring> #include <cstring>
#include <map> #include <map>
#include <random>
#include <regex> #include <regex>
#include <string> #include <string>
#include <utility> #include <utility>
#include <vector> #include <vector>
#include "fuzzers/tint_regex_fuzzer/util.h" #include "fuzzers/random_generator.h"
namespace tint { namespace tint {
namespace fuzzers { namespace fuzzers {
@ -137,7 +136,7 @@ void ReplaceInterval(size_t start_index,
bool SwapRandomIntervals(const std::string& delimiter, bool SwapRandomIntervals(const std::string& delimiter,
std::string& wgsl_code, std::string& wgsl_code,
std::mt19937& generator) { RandomGenerator& generator) {
std::vector<size_t> delimiter_positions = std::vector<size_t> delimiter_positions =
FindDelimiterIndices(delimiter, wgsl_code); FindDelimiterIndices(delimiter, wgsl_code);
@ -148,14 +147,10 @@ bool SwapRandomIntervals(const std::string& delimiter,
// When generating the i-th random number, we should make sure that there are // When generating the i-th random number, we should make sure that there are
// at least (3-i) numbers greater than this number. // at least (3-i) numbers greater than this number.
size_t ind1 = size_t ind1 = generator.GetUInt64(delimiter_positions.size() - 3u);
GetRandomIntFromRange(0, delimiter_positions.size() - 3U, generator); size_t ind2 = generator.GetUInt64(ind1 + 1u, delimiter_positions.size() - 2u);
size_t ind2 = GetRandomIntFromRange( size_t ind3 = generator.GetUInt64(ind2, delimiter_positions.size() - 2u);
ind1 + 1U, delimiter_positions.size() - 2U, generator); size_t ind4 = generator.GetUInt64(ind3 + 1u, delimiter_positions.size() - 1u);
size_t ind3 =
GetRandomIntFromRange(ind2, delimiter_positions.size() - 2U, generator);
size_t ind4 = GetRandomIntFromRange(
ind3 + 1U, delimiter_positions.size() - 1U, generator);
SwapIntervals(delimiter_positions[ind1], SwapIntervals(delimiter_positions[ind1],
delimiter_positions[ind2] - delimiter_positions[ind1], delimiter_positions[ind2] - delimiter_positions[ind1],
@ -168,7 +163,7 @@ bool SwapRandomIntervals(const std::string& delimiter,
bool DeleteRandomInterval(const std::string& delimiter, bool DeleteRandomInterval(const std::string& delimiter,
std::string& wgsl_code, std::string& wgsl_code,
std::mt19937& generator) { RandomGenerator& generator) {
std::vector<size_t> delimiter_positions = std::vector<size_t> delimiter_positions =
FindDelimiterIndices(delimiter, wgsl_code); FindDelimiterIndices(delimiter, wgsl_code);
@ -177,10 +172,8 @@ bool DeleteRandomInterval(const std::string& delimiter,
return false; return false;
} }
size_t ind1 = size_t ind1 = generator.GetUInt64(delimiter_positions.size() - 2u);
GetRandomIntFromRange(0, delimiter_positions.size() - 2U, generator); size_t ind2 = generator.GetUInt64(ind1 + 1u, delimiter_positions.size() - 1u);
size_t ind2 = GetRandomIntFromRange(
ind1 + 1U, delimiter_positions.size() - 1U, generator);
DeleteInterval(delimiter_positions[ind1], DeleteInterval(delimiter_positions[ind1],
delimiter_positions[ind2] - delimiter_positions[ind1], delimiter_positions[ind2] - delimiter_positions[ind1],
@ -191,7 +184,7 @@ bool DeleteRandomInterval(const std::string& delimiter,
bool DuplicateRandomInterval(const std::string& delimiter, bool DuplicateRandomInterval(const std::string& delimiter,
std::string& wgsl_code, std::string& wgsl_code,
std::mt19937& generator) { RandomGenerator& generator) {
std::vector<size_t> delimiter_positions = std::vector<size_t> delimiter_positions =
FindDelimiterIndices(delimiter, wgsl_code); FindDelimiterIndices(delimiter, wgsl_code);
@ -200,13 +193,9 @@ bool DuplicateRandomInterval(const std::string& delimiter,
return false; return false;
} }
size_t ind1 = size_t ind1 = generator.GetUInt64(delimiter_positions.size() - 2u);
GetRandomIntFromRange(0, delimiter_positions.size() - 2U, generator); size_t ind2 = generator.GetUInt64(ind1 + 1u, delimiter_positions.size() - 1u);
size_t ind2 = GetRandomIntFromRange( size_t ind3 = generator.GetUInt64(delimiter_positions.size() - 1u);
ind1 + 1U, delimiter_positions.size() - 1U, generator);
size_t ind3 =
GetRandomIntFromRange(0, delimiter_positions.size() - 1U, generator);
DuplicateInterval(delimiter_positions[ind1], DuplicateInterval(delimiter_positions[ind1],
delimiter_positions[ind2] - delimiter_positions[ind1], delimiter_positions[ind2] - delimiter_positions[ind1],
@ -215,7 +204,8 @@ bool DuplicateRandomInterval(const std::string& delimiter,
return true; return true;
} }
bool ReplaceRandomIdentifier(std::string& wgsl_code, std::mt19937& generator) { bool ReplaceRandomIdentifier(std::string& wgsl_code,
RandomGenerator& generator) {
std::vector<std::pair<size_t, size_t>> identifiers = std::vector<std::pair<size_t, size_t>> identifiers =
GetIdentifiers(wgsl_code); GetIdentifiers(wgsl_code);
@ -224,15 +214,12 @@ bool ReplaceRandomIdentifier(std::string& wgsl_code, std::mt19937& generator) {
return false; return false;
} }
size_t id1_index = size_t id1_index = generator.GetUInt64(identifiers.size() - 1u);
GetRandomIntFromRange(0, identifiers.size() - 1U, generator); size_t id2_index = generator.GetUInt64(identifiers.size() - 1u);
size_t id2_index =
GetRandomIntFromRange(0, identifiers.size() - 1U, generator);
// The two identifiers must be different // The two identifiers must be different
while (id1_index == id2_index) { while (id1_index == id2_index) {
id2_index = GetRandomIntFromRange(0, identifiers.size() - 1U, generator); id2_index = generator.GetUInt64(identifiers.size() - 1u);
} }
ReplaceRegion(identifiers[id1_index].first, identifiers[id1_index].second, ReplaceRegion(identifiers[id1_index].first, identifiers[id1_index].second,
@ -242,7 +229,8 @@ bool ReplaceRandomIdentifier(std::string& wgsl_code, std::mt19937& generator) {
return true; return true;
} }
bool ReplaceRandomIntLiteral(std::string& wgsl_code, std::mt19937& generator) { bool ReplaceRandomIntLiteral(std::string& wgsl_code,
RandomGenerator& generator) {
std::vector<std::pair<size_t, size_t>> literals = GetIntLiterals(wgsl_code); std::vector<std::pair<size_t, size_t>> literals = GetIntLiterals(wgsl_code);
// Need at least one integer literal // Need at least one integer literal
@ -250,14 +238,13 @@ bool ReplaceRandomIntLiteral(std::string& wgsl_code, std::mt19937& generator) {
return false; return false;
} }
size_t id1_index = GetRandomIntFromRange(0, literals.size() - 1U, generator); size_t id1_index = generator.GetUInt64(literals.size() - 1u);
// INT_MAX = 2147483647, INT_MIN = -2147483648 // INT_MAX = 2147483647, INT_MIN = -2147483648
std::vector<std::string> boundary_values = { std::vector<std::string> boundary_values = {
"2147483647", "-2147483648", "1", "-1", "0", "4294967295"}; "2147483647", "-2147483648", "1", "-1", "0", "4294967295"};
size_t boundary_index = size_t boundary_index = generator.GetUInt64(boundary_values.size() - 1u);
GetRandomIntFromRange(0, boundary_values.size() - 1U, generator);
ReplaceInterval(literals[id1_index].first, literals[id1_index].second, ReplaceInterval(literals[id1_index].first, literals[id1_index].second,
boundary_values[boundary_index], wgsl_code); boundary_values[boundary_index], wgsl_code);

View File

@ -15,11 +15,12 @@
#ifndef FUZZERS_TINT_REGEX_FUZZER_WGSL_MUTATOR_H_ #ifndef FUZZERS_TINT_REGEX_FUZZER_WGSL_MUTATOR_H_
#define FUZZERS_TINT_REGEX_FUZZER_WGSL_MUTATOR_H_ #define FUZZERS_TINT_REGEX_FUZZER_WGSL_MUTATOR_H_
#include <random>
#include <string> #include <string>
#include <utility> #include <utility>
#include <vector> #include <vector>
#include "fuzzers/random_generator.h"
namespace tint { namespace tint {
namespace fuzzers { namespace fuzzers {
namespace regex_fuzzer { namespace regex_fuzzer {
@ -114,7 +115,7 @@ void ReplaceInterval(size_t start_index,
/// @return true if a swap happened or false otherwise. /// @return true if a swap happened or false otherwise.
bool SwapRandomIntervals(const std::string& delimiter, bool SwapRandomIntervals(const std::string& delimiter,
std::string& wgsl_code, std::string& wgsl_code,
std::mt19937& generator); RandomGenerator& generator);
/// A function that, given a WGSL-like string and a delimiter, /// A function that, given a WGSL-like string and a delimiter,
/// generates another WGSL-like string by deleting a random /// generates another WGSL-like string by deleting a random
@ -125,7 +126,7 @@ bool SwapRandomIntervals(const std::string& delimiter,
/// @return true if a deletion happened or false otherwise. /// @return true if a deletion happened or false otherwise.
bool DeleteRandomInterval(const std::string& delimiter, bool DeleteRandomInterval(const std::string& delimiter,
std::string& wgsl_code, std::string& wgsl_code,
std::mt19937& generator); RandomGenerator& generator);
/// A function that, given a WGSL-like string and a delimiter, /// A function that, given a WGSL-like string and a delimiter,
/// generates another WGSL-like string by duplicating a random /// generates another WGSL-like string by duplicating a random
@ -136,20 +137,22 @@ bool DeleteRandomInterval(const std::string& delimiter,
/// @return true if a duplication happened or false otherwise. /// @return true if a duplication happened or false otherwise.
bool DuplicateRandomInterval(const std::string& delimiter, bool DuplicateRandomInterval(const std::string& delimiter,
std::string& wgsl_code, std::string& wgsl_code,
std::mt19937& generator); RandomGenerator& generator);
/// Replaces a randomly-chosen identifier in wgsl_code. /// Replaces a randomly-chosen identifier in wgsl_code.
/// @param wgsl_code - WGSL-like string where the replacement will occur. /// @param wgsl_code - WGSL-like string where the replacement will occur.
/// @param generator - the random number generator. /// @param generator - the random number generator.
/// @return true if a replacement happened or false otherwise. /// @return true if a replacement happened or false otherwise.
bool ReplaceRandomIdentifier(std::string& wgsl_code, std::mt19937& generator); bool ReplaceRandomIdentifier(std::string& wgsl_code,
RandomGenerator& generator);
/// Replaces the value of a randomly-chosen integer with one of /// Replaces the value of a randomly-chosen integer with one of
/// the values in the set {INT_MAX, INT_MIN, 0, -1}. /// the values in the set {INT_MAX, INT_MIN, 0, -1}.
/// @param wgsl_code - WGSL-like string where the replacement will occur. /// @param wgsl_code - WGSL-like string where the replacement will occur.
/// @param generator - the random number generator. /// @param generator - the random number generator.
/// @return true if a replacement happened or false otherwise. /// @return true if a replacement happened or false otherwise.
bool ReplaceRandomIntLiteral(std::string& wgsl_code, std::mt19937& generator); bool ReplaceRandomIntLiteral(std::string& wgsl_code,
RandomGenerator& generator);
} // namespace regex_fuzzer } // namespace regex_fuzzer
} // namespace fuzzers } // namespace fuzzers

View File

@ -13,6 +13,7 @@
# limitations under the License. # limitations under the License.
set(FUZZER_SOURCES set(FUZZER_SOURCES
../random_generator.cc
cli.cc cli.cc
fuzzer.cc fuzzer.cc
mutator.cc mutator.cc
@ -23,6 +24,7 @@ set(FUZZER_SOURCES
util.cc) util.cc)
set(FUZZER_SOURCES ${FUZZER_SOURCES} set(FUZZER_SOURCES ${FUZZER_SOURCES}
../random_generator.h
cli.h cli.h
mutator.h mutator.h
mutator_cache.h mutator_cache.h
@ -32,8 +34,8 @@ set(FUZZER_SOURCES ${FUZZER_SOURCES}
util.h) util.h)
set(FUZZER_SOURCES ${FUZZER_SOURCES} set(FUZZER_SOURCES ${FUZZER_SOURCES}
../tint_common_fuzzer.h ../tint_common_fuzzer.cc
../tint_common_fuzzer.cc) ../tint_common_fuzzer.h)
function(configure_spirv_tools_fuzzer_target NAME SOURCES) function(configure_spirv_tools_fuzzer_target NAME SOURCES)
add_executable(${NAME} ${SOURCES}) add_executable(${NAME} ${SOURCES})
@ -61,6 +63,7 @@ target_compile_definitions(tint_spirv_tools_fuzzer PRIVATE TARGET_FUZZER)
target_link_libraries(tint_spirv_tools_fuzzer libtint-fuzz) target_link_libraries(tint_spirv_tools_fuzzer libtint-fuzz)
set(DEBUGGER_SOURCES set(DEBUGGER_SOURCES
../random_generator.cc
cli.cc cli.cc
mutator.cc mutator.cc
mutator_debugger.cc mutator_debugger.cc
@ -70,6 +73,7 @@ set(DEBUGGER_SOURCES
util.cc) util.cc)
set(DEBUGGER_SOURCES ${DEBUGGER_SOURCES} set(DEBUGGER_SOURCES ${DEBUGGER_SOURCES}
../random_generator.h
cli.h cli.h
mutator.h mutator.h
spirv_fuzz_mutator.h spirv_fuzz_mutator.h

View File

@ -14,10 +14,10 @@
#include <cassert> #include <cassert>
#include <memory> #include <memory>
#include <random>
#include <string> #include <string>
#include <vector> #include <vector>
#include "fuzzers/random_generator.h"
#include "fuzzers/tint_common_fuzzer.h" #include "fuzzers/tint_common_fuzzer.h"
#include "fuzzers/tint_spirv_tools_fuzzer/cli.h" #include "fuzzers/tint_spirv_tools_fuzzer/cli.h"
#include "fuzzers/tint_spirv_tools_fuzzer/mutator_cache.h" #include "fuzzers/tint_spirv_tools_fuzzer/mutator_cache.h"
@ -67,9 +67,8 @@ std::unique_ptr<Mutator> CreateMutator(const std::vector<uint32_t>& binary,
} }
assert(!types.empty() && "At least one mutator type must be specified"); assert(!types.empty() && "At least one mutator type must be specified");
std::mt19937 rng(seed); RandomGenerator generator(seed);
auto mutator_type = auto mutator_type = types[generator.GetUInt64(types.size())];
types[std::uniform_int_distribution<size_t>(0, types.size() - 1)(rng)];
const auto& mutator_params = context->params.mutator_params; const auto& mutator_params = context->params.mutator_params;
switch (mutator_type) { switch (mutator_type) {

View File

@ -66,7 +66,7 @@ SpirvOptMutator::SpirvOptMutator(spv_target_env target_env,
optimized_binary_(), optimized_binary_(),
validate_after_each_opt_(validate_after_each_opt), validate_after_each_opt_(validate_after_each_opt),
opt_batch_size_(opt_batch_size), opt_batch_size_(opt_batch_size),
rng_(seed) { generator_(seed) {
assert(spvtools::SpirvTools(target_env).Validate(original_binary_) && assert(spvtools::SpirvTools(target_env).Validate(original_binary_) &&
"Initial binary is invalid"); "Initial binary is invalid");
assert(!opt_passes_.empty() && "Must be at least one pass"); assert(!opt_passes_.empty() && "Must be at least one pass");
@ -105,8 +105,7 @@ SpirvOptMutator::Result SpirvOptMutator::Mutate() {
std::vector<std::string> passes; std::vector<std::string> passes;
while (passes.size() < num_of_passes) { while (passes.size() < num_of_passes) {
auto idx = std::uniform_int_distribution<size_t>( auto idx = generator_.GetUInt64(opt_passes_.size());
0, opt_passes_.size() - 1)(rng_);
passes.push_back(opt_passes_[idx]); passes.push_back(opt_passes_[idx]);
} }

View File

@ -15,11 +15,11 @@
#ifndef FUZZERS_TINT_SPIRV_TOOLS_FUZZER_SPIRV_OPT_MUTATOR_H_ #ifndef FUZZERS_TINT_SPIRV_TOOLS_FUZZER_SPIRV_OPT_MUTATOR_H_
#define FUZZERS_TINT_SPIRV_TOOLS_FUZZER_SPIRV_OPT_MUTATOR_H_ #define FUZZERS_TINT_SPIRV_TOOLS_FUZZER_SPIRV_OPT_MUTATOR_H_
#include <random>
#include <sstream> #include <sstream>
#include <string> #include <string>
#include <vector> #include <vector>
#include "fuzzers/random_generator.h"
#include "fuzzers/tint_spirv_tools_fuzzer/mutator.h" #include "fuzzers/tint_spirv_tools_fuzzer/mutator.h"
#include "spirv-tools/libspirv.h" #include "spirv-tools/libspirv.h"
@ -86,7 +86,7 @@ class SpirvOptMutator : public Mutator {
std::stringstream errors_; std::stringstream errors_;
// The random number generator initialized with `seed_`. // The random number generator initialized with `seed_`.
std::mt19937 rng_; RandomGenerator generator_;
}; };
} // namespace spvtools_fuzzer } // namespace spvtools_fuzzer

View File

@ -44,7 +44,7 @@ SpirvReduceMutator::SpirvReduceMutator(spv_target_env target_env,
bool validate_after_each_reduction) bool validate_after_each_reduction)
: ir_context_(nullptr), : ir_context_(nullptr),
finders_(), finders_(),
rng_(seed), generator_(seed),
errors_(), errors_(),
is_valid_(true), is_valid_(true),
reductions_batch_size_(reductions_batch_size), reductions_batch_size_(reductions_batch_size),

View File

@ -16,12 +16,12 @@
#define FUZZERS_TINT_SPIRV_TOOLS_FUZZER_SPIRV_REDUCE_MUTATOR_H_ #define FUZZERS_TINT_SPIRV_TOOLS_FUZZER_SPIRV_REDUCE_MUTATOR_H_
#include <memory> #include <memory>
#include <random>
#include <sstream> #include <sstream>
#include <string> #include <string>
#include <utility> #include <utility>
#include <vector> #include <vector>
#include "fuzzers/random_generator.h"
#include "fuzzers/tint_spirv_tools_fuzzer/mutator.h" #include "fuzzers/tint_spirv_tools_fuzzer/mutator.h"
#include "source/reduce/reduction_opportunity_finder.h" #include "source/reduce/reduction_opportunity_finder.h"
@ -65,7 +65,7 @@ class SpirvReduceMutator : public Mutator {
private: private:
template <typename T, typename... Args> template <typename T, typename... Args>
void MaybeAddFinder(Args&&... args) { void MaybeAddFinder(Args&&... args) {
if (enable_all_reductions_ || std::uniform_int_distribution<>(0, 1)(rng_)) { if (enable_all_reductions_ || generator_.GetBool()) {
finders_.push_back(std::make_unique<T>(std::forward<Args>(args)...)); finders_.push_back(std::make_unique<T>(std::forward<Args>(args)...));
} }
} }
@ -73,16 +73,14 @@ class SpirvReduceMutator : public Mutator {
template <typename T> template <typename T>
T* GetRandomElement(std::vector<T>* arr) { T* GetRandomElement(std::vector<T>* arr) {
assert(!arr->empty() && "Can't get random element from an empty vector"); assert(!arr->empty() && "Can't get random element from an empty vector");
auto index = auto index = generator_.GetUInt64(arr->size());
std::uniform_int_distribution<size_t>(0, arr->size() - 1)(rng_);
return &(*arr)[index]; return &(*arr)[index];
} }
template <typename T> template <typename T>
T* GetRandomElement(std::vector<std::unique_ptr<T>>* arr) { T* GetRandomElement(std::vector<std::unique_ptr<T>>* arr) {
assert(!arr->empty() && "Can't get random element from an empty vector"); assert(!arr->empty() && "Can't get random element from an empty vector");
auto index = auto index = generator_.GetUInt64(arr->size());
std::uniform_int_distribution<size_t>(0, arr->size() - 1)(rng_);
return (*arr)[index].get(); return (*arr)[index].get();
} }
@ -97,7 +95,7 @@ class SpirvReduceMutator : public Mutator {
finders_; finders_;
// Random number generator initialized with `seed_`. // Random number generator initialized with `seed_`.
std::mt19937 rng_; RandomGenerator generator_;
// All the errors produced by the reducer. // All the errors produced by the reducer.
std::stringstream errors_; std::stringstream errors_;