| // Copyright (c) 2021 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. |
| |
| #include <cstdint> |
| #include <vector> |
| |
| #include "source/fuzz/fuzzer.h" |
| #include "source/fuzz/pseudo_random_generator.h" |
| #include "spirv-tools/libspirv.hpp" |
| #include "test/fuzzers/random_generator.h" |
| |
| extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { |
| if (size == 0 || (size % sizeof(uint32_t)) != 0) { |
| // An empty binary, or a binary whose size is not a multiple of word-size, |
| // cannot be valid, so can be rejected immediately. |
| return 0; |
| } |
| |
| std::vector<uint32_t> initial_binary(size / sizeof(uint32_t)); |
| memcpy(initial_binary.data(), data, size); |
| |
| spvtools::ValidatorOptions validator_options; |
| |
| spvtools::MessageConsumer message_consumer = |
| [](spv_message_level_t, const char*, const spv_position_t&, const char*) { |
| }; |
| |
| spvtools::fuzzers::RandomGenerator random_gen(data, size); |
| auto target_env = random_gen.GetTargetEnv(); |
| std::unique_ptr<spvtools::opt::IRContext> ir_context; |
| if (!spvtools::fuzz::fuzzerutil::BuildIRContext( |
| target_env, message_consumer, initial_binary, validator_options, |
| &ir_context)) { |
| // The input is invalid - give up. |
| return 0; |
| } |
| |
| std::vector<spvtools::fuzz::fuzzerutil::ModuleSupplier> donor_suppliers = { |
| [&initial_binary, message_consumer, target_env, |
| &validator_options]() -> std::unique_ptr<spvtools::opt::IRContext> { |
| std::unique_ptr<spvtools::opt::IRContext> result; |
| if (!spvtools::fuzz::fuzzerutil::BuildIRContext( |
| target_env, message_consumer, initial_binary, validator_options, |
| &result)) { |
| // The input was successfully parsed and validated first time around, |
| // so something is wrong if it is now invalid. |
| abort(); |
| } |
| return result; |
| }}; |
| |
| uint32_t seed = random_gen.GetUInt32(std::numeric_limits<uint32_t>::max()); |
| auto fuzzer_context = spvtools::MakeUnique<spvtools::fuzz::FuzzerContext>( |
| spvtools::MakeUnique<spvtools::fuzz::PseudoRandomGenerator>(seed), |
| spvtools::fuzz::FuzzerContext::GetMinFreshId(ir_context.get()), false); |
| |
| auto transformation_context = |
| spvtools::MakeUnique<spvtools::fuzz::TransformationContext>( |
| spvtools::MakeUnique<spvtools::fuzz::FactManager>(ir_context.get()), |
| validator_options); |
| |
| spvtools::fuzz::Fuzzer fuzzer( |
| std::move(ir_context), std::move(transformation_context), |
| std::move(fuzzer_context), message_consumer, donor_suppliers, false, |
| spvtools::fuzz::RepeatedPassStrategy::kLoopedWithRecommendations, true, |
| validator_options); |
| fuzzer.Run(0); |
| return 0; |
| } |