You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
188 lines
7.4 KiB
188 lines
7.4 KiB
// Copyright (c) 2019 Google LLC
|
|
//
|
|
// 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 SOURCE_FUZZ_FUZZER_H_
|
|
#define SOURCE_FUZZ_FUZZER_H_
|
|
|
|
#include <memory>
|
|
#include <utility>
|
|
#include <vector>
|
|
|
|
#include "source/fuzz/fuzzer_context.h"
|
|
#include "source/fuzz/fuzzer_pass.h"
|
|
#include "source/fuzz/fuzzer_util.h"
|
|
#include "source/fuzz/pass_management/repeated_pass_instances.h"
|
|
#include "source/fuzz/pass_management/repeated_pass_recommender.h"
|
|
#include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
|
|
#include "source/fuzz/random_generator.h"
|
|
#include "source/opt/ir_context.h"
|
|
#include "spirv-tools/libspirv.hpp"
|
|
|
|
namespace spvtools {
|
|
namespace fuzz {
|
|
|
|
// Transforms a SPIR-V module into a semantically equivalent SPIR-V module by
|
|
// running a number of randomized fuzzer passes.
|
|
class Fuzzer {
|
|
public:
|
|
// Possible statuses that can result from running the fuzzer.
|
|
enum class FuzzerResultStatus {
|
|
kComplete,
|
|
kFailedToCreateSpirvToolsInterface,
|
|
kFuzzerPassLedToInvalidModule,
|
|
kInitialBinaryInvalid,
|
|
};
|
|
|
|
struct FuzzerResult {
|
|
FuzzerResultStatus status;
|
|
std::vector<uint32_t> transformed_binary;
|
|
protobufs::TransformationSequence applied_transformations;
|
|
};
|
|
|
|
// Each field of this enum corresponds to an available repeated pass
|
|
// strategy, and is used to decide which kind of RepeatedPassManager object
|
|
// to create.
|
|
enum class RepeatedPassStrategy {
|
|
kSimple,
|
|
kRandomWithRecommendations,
|
|
kLoopedWithRecommendations
|
|
};
|
|
|
|
Fuzzer(spv_target_env target_env, MessageConsumer consumer,
|
|
const std::vector<uint32_t>& binary_in,
|
|
const protobufs::FactSequence& initial_facts,
|
|
const std::vector<fuzzerutil::ModuleSupplier>& donor_suppliers,
|
|
std::unique_ptr<RandomGenerator> random_generator,
|
|
bool enable_all_passes, RepeatedPassStrategy repeated_pass_strategy,
|
|
bool validate_after_each_fuzzer_pass,
|
|
spv_validator_options validator_options);
|
|
|
|
// Disables copy/move constructor/assignment operations.
|
|
Fuzzer(const Fuzzer&) = delete;
|
|
Fuzzer(Fuzzer&&) = delete;
|
|
Fuzzer& operator=(const Fuzzer&) = delete;
|
|
Fuzzer& operator=(Fuzzer&&) = delete;
|
|
|
|
~Fuzzer();
|
|
|
|
// Transforms |binary_in_| by running a number of randomized fuzzer passes.
|
|
// Initial facts about the input binary and the context in which it will
|
|
// execute are provided via |initial_facts_|. A source of donor modules to be
|
|
// used by transformations is provided via |donor_suppliers_|. On success,
|
|
// returns a successful result status together with the transformed binary and
|
|
// the sequence of transformations that were applied. Otherwise, returns an
|
|
// appropriate result status together with an empty binary and empty
|
|
// transformation sequence.
|
|
FuzzerResult Run();
|
|
|
|
private:
|
|
// A convenience method to add a repeated fuzzer pass to |pass_instances| with
|
|
// probability |percentage_chance_of_adding_pass|%, or with probability 100%
|
|
// if |enable_all_passes_| is true.
|
|
//
|
|
// All fuzzer passes take members |ir_context_|, |transformation_context_|,
|
|
// |fuzzer_context_| and |transformation_sequence_out_| as parameters. Extra
|
|
// arguments can be provided via |extra_args|.
|
|
template <typename FuzzerPassT, typename... Args>
|
|
void MaybeAddRepeatedPass(uint32_t percentage_chance_of_adding_pass,
|
|
RepeatedPassInstances* pass_instances,
|
|
Args&&... extra_args);
|
|
|
|
// The same as the above, with |percentage_chance_of_adding_pass| == 50%.
|
|
template <typename FuzzerPassT, typename... Args>
|
|
void MaybeAddRepeatedPass(RepeatedPassInstances* pass_instances,
|
|
Args&&... extra_args) {
|
|
MaybeAddRepeatedPass<FuzzerPassT>(50, pass_instances,
|
|
std::forward<Args>(extra_args)...);
|
|
}
|
|
|
|
// A convenience method to add a final fuzzer pass to |passes| with
|
|
// probability 50%, or with probability 100% if |enable_all_passes_| is true.
|
|
//
|
|
// All fuzzer passes take members |ir_context_|, |transformation_context_|,
|
|
// |fuzzer_context_| and |transformation_sequence_out_| as parameters. Extra
|
|
// arguments can be provided via |extra_args|.
|
|
template <typename FuzzerPassT, typename... Args>
|
|
void MaybeAddFinalPass(std::vector<std::unique_ptr<FuzzerPass>>* passes,
|
|
Args&&... extra_args);
|
|
|
|
// Decides whether to apply more repeated passes. The probability decreases as
|
|
// the number of transformations that have been applied increases.
|
|
bool ShouldContinueFuzzing();
|
|
|
|
// Applies |pass|, which must be a pass constructed with |ir_context|.
|
|
// If |validate_after_each_fuzzer_pass_| is not set, true is always returned.
|
|
// Otherwise, true is returned if and only if |ir_context| passes validation,
|
|
// every block has its enclosing function as its parent, and every
|
|
// instruction has a distinct unique id.
|
|
bool ApplyPassAndCheckValidity(FuzzerPass* pass) const;
|
|
|
|
// Target environment.
|
|
const spv_target_env target_env_;
|
|
|
|
// Message consumer that will be invoked once for each message communicated
|
|
// from the library.
|
|
MessageConsumer consumer_;
|
|
|
|
// The initial binary to which fuzzing should be applied.
|
|
const std::vector<uint32_t>& binary_in_;
|
|
|
|
// Initial facts known to hold in advance of applying any transformations.
|
|
const protobufs::FactSequence& initial_facts_;
|
|
|
|
// A source of modules whose contents can be donated into the module being
|
|
// fuzzed.
|
|
const std::vector<fuzzerutil::ModuleSupplier>& donor_suppliers_;
|
|
|
|
// Random number generator to control decision making during fuzzing.
|
|
std::unique_ptr<RandomGenerator> random_generator_;
|
|
|
|
// Determines whether all passes should be enabled, vs. having passes be
|
|
// probabilistically enabled.
|
|
bool enable_all_passes_;
|
|
|
|
// Controls which type of RepeatedPassManager object to create.
|
|
RepeatedPassStrategy repeated_pass_strategy_;
|
|
|
|
// Determines whether the validator should be invoked after every fuzzer pass.
|
|
bool validate_after_each_fuzzer_pass_;
|
|
|
|
// Options to control validation.
|
|
spv_validator_options validator_options_;
|
|
|
|
// The number of repeated fuzzer passes that have been applied is kept track
|
|
// of, in order to enforce a hard limit on the number of times such passes
|
|
// can be applied.
|
|
uint32_t num_repeated_passes_applied_;
|
|
|
|
// Intermediate representation for the module being fuzzed, which gets
|
|
// mutated as fuzzing proceeds.
|
|
std::unique_ptr<opt::IRContext> ir_context_;
|
|
|
|
// Provides probabilities that control the fuzzing process.
|
|
std::unique_ptr<FuzzerContext> fuzzer_context_;
|
|
|
|
// Contextual information that is required in order to apply transformations.
|
|
std::unique_ptr<TransformationContext> transformation_context_;
|
|
|
|
// The sequence of transformations that have been applied during fuzzing. It
|
|
// is initially empty and grows as fuzzer passes are applied.
|
|
protobufs::TransformationSequence transformation_sequence_out_;
|
|
};
|
|
|
|
} // namespace fuzz
|
|
} // namespace spvtools
|
|
|
|
#endif // SOURCE_FUZZ_FUZZER_H_
|