| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187 |
- // 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_
|