Add library for spirv-fuzz (#2618)
Adds a library for spirv-fuzz, consisting of a Fuzzer class that will
transform a module with respect to (a) facts about the module provided
via a FactManager class, and (b) a source of random numbers and
parameters to control the transformation process provided via a
FuzzerContext class. Transformations will be applied via classes that
implement a FuzzerPass interface, and both facts and transformations
will be represented via protobuf messages. Currently there are no
concrete facts, transformations nor fuzzer passes; these will follow.
diff --git a/include/spirv-tools/libspirv.h b/include/spirv-tools/libspirv.h
index 5cea101..82717e9 100644
--- a/include/spirv-tools/libspirv.h
+++ b/include/spirv-tools/libspirv.h
@@ -370,6 +370,8 @@
typedef struct spv_reducer_options_t spv_reducer_options_t;
+typedef struct spv_fuzzer_options_t spv_fuzzer_options_t;
+
// Type Definitions
typedef spv_const_binary_t* spv_const_binary;
@@ -385,6 +387,8 @@
typedef const spv_optimizer_options_t* spv_const_optimizer_options;
typedef spv_reducer_options_t* spv_reducer_options;
typedef const spv_reducer_options_t* spv_const_reducer_options;
+typedef spv_fuzzer_options_t* spv_fuzzer_options;
+typedef const spv_fuzzer_options_t* spv_const_fuzzer_options;
// Platform API
@@ -590,6 +594,19 @@
SPIRV_TOOLS_EXPORT void spvReducerOptionsSetFailOnValidationError(
spv_reducer_options options, bool fail_on_validation_error);
+// Creates a fuzzer options object with default options. Returns a valid
+// options object. The object remains valid until it is passed into
+// |spvFuzzerOptionsDestroy|.
+SPIRV_TOOLS_EXPORT spv_fuzzer_options spvFuzzerOptionsCreate();
+
+// Destroys the given fuzzer options object.
+SPIRV_TOOLS_EXPORT void spvFuzzerOptionsDestroy(spv_fuzzer_options options);
+
+// Sets the seed with which the random number generator used by the fuzzer
+// should be initialized.
+SPIRV_TOOLS_EXPORT void spvFuzzerOptionsSetRandomSeed(
+ spv_fuzzer_options options, uint32_t seed);
+
// Encodes the given SPIR-V assembly text to its binary representation. The
// length parameter specifies the number of bytes for text. Encoded binary will
// be stored into *binary. Any error will be written into *diagnostic if
diff --git a/include/spirv-tools/libspirv.hpp b/include/spirv-tools/libspirv.hpp
index da27404..b0fd4a2 100644
--- a/include/spirv-tools/libspirv.hpp
+++ b/include/spirv-tools/libspirv.hpp
@@ -191,6 +191,26 @@
spv_reducer_options options_;
};
+// A C++ wrapper around a fuzzer options object.
+class FuzzerOptions {
+ public:
+ FuzzerOptions() : options_(spvFuzzerOptionsCreate()) {}
+ ~FuzzerOptions() { spvFuzzerOptionsDestroy(options_); }
+
+ // Allow implicit conversion to the underlying object.
+ operator spv_fuzzer_options() const { // NOLINT(google-explicit-constructor)
+ return options_;
+ }
+
+ // See spvFuzzerOptionsSetRandomSeed.
+ void set_random_seed(uint32_t seed) {
+ spvFuzzerOptionsSetRandomSeed(options_, seed);
+ }
+
+ private:
+ spv_fuzzer_options options_;
+};
+
// C++ interface for SPIRV-Tools functionalities. It wraps the context
// (including target environment and the corresponding SPIR-V grammar) and
// provides methods for assembling, disassembling, and validating.
diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt
index 0c0820d..93938f0 100644
--- a/source/CMakeLists.txt
+++ b/source/CMakeLists.txt
@@ -198,6 +198,7 @@
add_subdirectory(opt)
add_subdirectory(reduce)
+add_subdirectory(fuzz)
add_subdirectory(link)
set(SPIRV_SOURCES
@@ -233,6 +234,7 @@
${CMAKE_CURRENT_SOURCE_DIR}/spirv_constant.h
${CMAKE_CURRENT_SOURCE_DIR}/spirv_definition.h
${CMAKE_CURRENT_SOURCE_DIR}/spirv_endian.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/spirv_fuzzer_options.h
${CMAKE_CURRENT_SOURCE_DIR}/spirv_optimizer_options.h
${CMAKE_CURRENT_SOURCE_DIR}/spirv_reducer_options.h
${CMAKE_CURRENT_SOURCE_DIR}/spirv_target_env.h
@@ -260,6 +262,7 @@
${CMAKE_CURRENT_SOURCE_DIR}/print.cpp
${CMAKE_CURRENT_SOURCE_DIR}/software_version.cpp
${CMAKE_CURRENT_SOURCE_DIR}/spirv_endian.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/spirv_fuzzer_options.cpp
${CMAKE_CURRENT_SOURCE_DIR}/spirv_optimizer_options.cpp
${CMAKE_CURRENT_SOURCE_DIR}/spirv_reducer_options.cpp
${CMAKE_CURRENT_SOURCE_DIR}/spirv_target_env.cpp
diff --git a/source/fuzz/CMakeLists.txt b/source/fuzz/CMakeLists.txt
new file mode 100644
index 0000000..af25904
--- /dev/null
+++ b/source/fuzz/CMakeLists.txt
@@ -0,0 +1,90 @@
+# 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.
+
+if(SPIRV_BUILD_FUZZER)
+ set(PROTOBUF_SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/protobufs/spvtoolsfuzz.proto)
+
+ add_custom_command(
+ OUTPUT protobufs/spvtoolsfuzz.pb.cc protobufs/spvtoolsfuzz.pb.h
+ COMMAND protobuf::protoc
+ -I=${CMAKE_CURRENT_SOURCE_DIR}/protobufs
+ --cpp_out=protobufs
+ ${PROTOBUF_SOURCE}
+ DEPENDS ${PROTOBUF_SOURCE}
+ COMMENT "Generate protobuf sources from proto definition file."
+ )
+
+ set(SPIRV_TOOLS_FUZZ_SOURCES
+ fact_manager.h
+ fuzzer.h
+ fuzzer_context.h
+ fuzzer_pass.h
+ protobufs/spirvfuzz_protobufs.h
+ pseudo_random_generator.h
+ random_generator.h
+ ${CMAKE_CURRENT_BINARY_DIR}/protobufs/spvtoolsfuzz.pb.h
+
+ fact_manager.cpp
+ fuzzer.cpp
+ fuzzer_context.cpp
+ fuzzer_pass.cpp
+ pseudo_random_generator.cpp
+ random_generator.cpp
+ ${CMAKE_CURRENT_BINARY_DIR}/protobufs/spvtoolsfuzz.pb.cc
+ )
+
+ if(MSVC)
+ # Enable parallel builds across four cores for this lib
+ add_definitions(/MP4)
+ endif()
+
+ spvtools_pch(SPIRV_TOOLS_FUZZ_SOURCES pch_source_fuzz)
+
+ add_library(SPIRV-Tools-fuzz ${SPIRV_TOOLS_FUZZ_SOURCES})
+
+ spvtools_default_compile_options(SPIRV-Tools-fuzz)
+ target_compile_definitions(SPIRV-Tools-fuzz PUBLIC -DGOOGLE_PROTOBUF_NO_RTTI -DGOOGLE_PROTOBUF_USE_UNALIGNED=0)
+
+ # Compilation of the auto-generated protobuf source file will yield warnings,
+ # which we have no control over and thus wish to ignore.
+ if(${COMPILER_IS_LIKE_GNU})
+ set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/protobufs/spvtoolsfuzz.pb.cc PROPERTIES COMPILE_FLAGS -w)
+ endif()
+ if(MSVC)
+ set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/protobufs/spvtoolsfuzz.pb.cc PROPERTIES COMPILE_FLAGS /w)
+ endif()
+
+ target_include_directories(SPIRV-Tools-fuzz
+ PUBLIC ${spirv-tools_SOURCE_DIR}/include
+ PUBLIC ${SPIRV_HEADER_INCLUDE_DIR}
+ PRIVATE ${spirv-tools_BINARY_DIR}
+ PRIVATE ${CMAKE_BINARY_DIR})
+
+ # The fuzzer reuses a lot of functionality from the SPIRV-Tools library.
+ target_link_libraries(SPIRV-Tools-fuzz
+ PUBLIC ${SPIRV_TOOLS}
+ PUBLIC SPIRV-Tools-opt
+ PUBLIC protobuf::libprotobuf)
+
+ set_property(TARGET SPIRV-Tools-fuzz PROPERTY FOLDER "SPIRV-Tools libraries")
+ spvtools_check_symbol_exports(SPIRV-Tools-fuzz)
+
+ if(ENABLE_SPIRV_TOOLS_INSTALL)
+ install(TARGETS SPIRV-Tools-fuzz
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
+ endif(ENABLE_SPIRV_TOOLS_INSTALL)
+
+endif(SPIRV_BUILD_FUZZER)
diff --git a/source/fuzz/fact_manager.cpp b/source/fuzz/fact_manager.cpp
new file mode 100644
index 0000000..1c19287
--- /dev/null
+++ b/source/fuzz/fact_manager.cpp
@@ -0,0 +1,46 @@
+// 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.
+
+#include <utility>
+
+#include "source/fuzz/fact_manager.h"
+#include "source/opt/ir_context.h"
+
+namespace spvtools {
+namespace fuzz {
+
+FactManager::FactManager() = default;
+
+FactManager::~FactManager() = default;
+
+bool FactManager::AddFacts(const protobufs::FactSequence& initial_facts,
+ opt::IRContext* context) {
+ for (auto& fact : initial_facts.fact()) {
+ if (!AddFact(fact, context)) {
+ // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/2621) Provide
+ // information about the fact that could not be added.
+ return false;
+ }
+ }
+ return true;
+}
+
+bool FactManager::AddFact(const spvtools::fuzz::protobufs::Fact&,
+ spvtools::opt::IRContext*) {
+ assert(0 && "No facts are yet supported.");
+ return true;
+}
+
+} // namespace fuzz
+} // namespace spvtools
diff --git a/source/fuzz/fact_manager.h b/source/fuzz/fact_manager.h
new file mode 100644
index 0000000..49b6d6d
--- /dev/null
+++ b/source/fuzz/fact_manager.h
@@ -0,0 +1,53 @@
+// 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_FACT_MANAGER_H_
+#define SOURCE_FUZZ_FACT_MANAGER_H_
+
+#include <utility>
+
+#include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
+#include "source/opt/constants.h"
+
+namespace spvtools {
+namespace fuzz {
+
+// Keeps track of facts about the module being transformed on which the fuzzing
+// process can depend. Some initial facts can be provided, for example about
+// guarantees on the values of inputs to SPIR-V entry points. Transformations
+// may then rely on these facts, can add further facts that they establish.
+// Facts are intended to be simple properties that either cannot be deduced from
+// the module (such as properties that are guaranteed to hold for entry point
+// inputs), or that are established by transformations, likely to be useful for
+// future transformations, and not completely trivial to deduce straight from
+// the module.
+class FactManager {
+ public:
+ FactManager();
+
+ ~FactManager();
+
+ // Adds all the facts from |facts|, checking them for validity with respect to
+ // |context|. Returns true if and only if all facts are valid.
+ bool AddFacts(const protobufs::FactSequence& facts, opt::IRContext* context);
+
+ // Adds |fact| to the fact manager, checking it for validity with respect to
+ // |context|. Returns true if and only if the fact is valid.
+ bool AddFact(const protobufs::Fact& fact, opt::IRContext* context);
+};
+
+} // namespace fuzz
+} // namespace spvtools
+
+#endif // #define SOURCE_FUZZ_FACT_MANAGER_H_
diff --git a/source/fuzz/fuzzer.cpp b/source/fuzz/fuzzer.cpp
new file mode 100644
index 0000000..2f28d79
--- /dev/null
+++ b/source/fuzz/fuzzer.cpp
@@ -0,0 +1,109 @@
+// 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.
+
+#include "source/fuzz/fuzzer.h"
+
+#include <cassert>
+#include <sstream>
+
+#include "source/fuzz/fact_manager.h"
+#include "source/fuzz/fuzzer_context.h"
+#include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
+#include "source/fuzz/pseudo_random_generator.h"
+#include "source/opt/build_module.h"
+#include "source/spirv_fuzzer_options.h"
+#include "source/util/make_unique.h"
+
+namespace spvtools {
+namespace fuzz {
+
+namespace {
+const uint32_t kIdBoundGap = 100;
+}
+
+struct Fuzzer::Impl {
+ explicit Impl(spv_target_env env) : target_env(env) {}
+
+ const spv_target_env target_env; // Target environment.
+ MessageConsumer consumer; // Message consumer.
+};
+
+Fuzzer::Fuzzer(spv_target_env env) : impl_(MakeUnique<Impl>(env)) {}
+
+Fuzzer::~Fuzzer() = default;
+
+void Fuzzer::SetMessageConsumer(MessageConsumer c) {
+ impl_->consumer = std::move(c);
+}
+
+Fuzzer::FuzzerResultStatus Fuzzer::Run(
+ const std::vector<uint32_t>& binary_in,
+ const protobufs::FactSequence& initial_facts,
+ std::vector<uint32_t>* binary_out, protobufs::TransformationSequence*,
+ spv_const_fuzzer_options options) const {
+ // Check compatibility between the library version being linked with and the
+ // header files being used.
+ GOOGLE_PROTOBUF_VERIFY_VERSION;
+
+ spvtools::SpirvTools tools(impl_->target_env);
+ if (!tools.IsValid()) {
+ impl_->consumer(SPV_MSG_ERROR, nullptr, {},
+ "Failed to create SPIRV-Tools interface; stopping.");
+ return Fuzzer::FuzzerResultStatus::kFailedToCreateSpirvToolsInterface;
+ }
+
+ // Initial binary should be valid.
+ if (!tools.Validate(&binary_in[0], binary_in.size())) {
+ impl_->consumer(SPV_MSG_ERROR, nullptr, {},
+ "Initial binary is invalid; stopping.");
+ return Fuzzer::FuzzerResultStatus::kInitialBinaryInvalid;
+ }
+
+ // Build the module from the input binary.
+ std::unique_ptr<opt::IRContext> ir_context = BuildModule(
+ impl_->target_env, impl_->consumer, binary_in.data(), binary_in.size());
+ assert(ir_context);
+
+ // Make a PRNG, either from a given seed or from a random device.
+ PseudoRandomGenerator random_generator(
+ options->has_random_seed ? options->random_seed
+ : (uint32_t)std::random_device()());
+
+ // The fuzzer will introduce new ids into the module. The module's id bound
+ // gives the smallest id that can be used for this purpose. We add an offset
+ // to this so that there is a sizeable gap between the ids used in the
+ // original module and the ids used for fuzzing, as a readability aid.
+ //
+ // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/2541) consider the
+ // case where the maximum id bound is reached.
+ auto minimum_fresh_id = ir_context->module()->id_bound() + kIdBoundGap;
+ FuzzerContext fuzzer_context(&random_generator, minimum_fresh_id);
+
+ FactManager fact_manager;
+ if (!fact_manager.AddFacts(initial_facts, ir_context.get())) {
+ return Fuzzer::FuzzerResultStatus::kInitialFactsInvalid;
+ }
+
+ // Fuzzer passes will be created and applied here and will populate the
+ // output sequence of transformations. Currently there are no passes.
+ // TODO(afd) Implement fuzzer passes and invoke them here.
+
+ // Encode the module as a binary.
+ ir_context->module()->ToBinary(binary_out, false);
+
+ return Fuzzer::FuzzerResultStatus::kComplete;
+}
+
+} // namespace fuzz
+} // namespace spvtools
diff --git a/source/fuzz/fuzzer.h b/source/fuzz/fuzzer.h
new file mode 100644
index 0000000..f81f297
--- /dev/null
+++ b/source/fuzz/fuzzer.h
@@ -0,0 +1,74 @@
+// 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 <vector>
+
+#include "source/fuzz/protobufs/spirvfuzz_protobufs.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,
+ kInitialBinaryInvalid,
+ kInitialFactsInvalid,
+ };
+
+ // Constructs a fuzzer from the given target environment.
+ explicit Fuzzer(spv_target_env env);
+
+ // Disables copy/move constructor/assignment operations.
+ Fuzzer(const Fuzzer&) = delete;
+ Fuzzer(Fuzzer&&) = delete;
+ Fuzzer& operator=(const Fuzzer&) = delete;
+ Fuzzer& operator=(Fuzzer&&) = delete;
+
+ ~Fuzzer();
+
+ // Sets the message consumer to the given |consumer|. The |consumer| will be
+ // invoked once for each message communicated from the library.
+ void SetMessageConsumer(MessageConsumer consumer);
+
+ // Transforms |binary_in| to |binary_out| by running a number of randomized
+ // fuzzer passes, controlled via |options|. Initial facts about the input
+ // binary and the context in which it will execute are provided via
+ // |initial_facts|. The transformation sequence that was applied is returned
+ // via |transformation_sequence_out|.
+ FuzzerResultStatus Run(
+ const std::vector<uint32_t>& binary_in,
+ const protobufs::FactSequence& initial_facts,
+ std::vector<uint32_t>* binary_out,
+ protobufs::TransformationSequence* transformation_sequence_out,
+ spv_const_fuzzer_options options) const;
+
+ private:
+ struct Impl; // Opaque struct for holding internal data.
+ std::unique_ptr<Impl> impl_; // Unique pointer to internal data.
+};
+
+} // namespace fuzz
+} // namespace spvtools
+
+#endif // SOURCE_FUZZ_FUZZER_H_
diff --git a/source/fuzz/fuzzer_context.cpp b/source/fuzz/fuzzer_context.cpp
new file mode 100644
index 0000000..11de612
--- /dev/null
+++ b/source/fuzz/fuzzer_context.cpp
@@ -0,0 +1,33 @@
+// 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.
+
+#include "source/fuzz/fuzzer_context.h"
+
+namespace spvtools {
+namespace fuzz {
+
+FuzzerContext::FuzzerContext(RandomGenerator* random_generator,
+ uint32_t min_fresh_id)
+ : random_generator_(random_generator), next_fresh_id_(min_fresh_id) {}
+
+FuzzerContext::~FuzzerContext() = default;
+
+uint32_t FuzzerContext::GetFreshId() { return next_fresh_id_++; }
+
+RandomGenerator* FuzzerContext::GetRandomGenerator() {
+ return random_generator_;
+}
+
+} // namespace fuzz
+} // namespace spvtools
diff --git a/source/fuzz/fuzzer_context.h b/source/fuzz/fuzzer_context.h
new file mode 100644
index 0000000..5ab0f6f
--- /dev/null
+++ b/source/fuzz/fuzzer_context.h
@@ -0,0 +1,52 @@
+// 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_CONTEXT_H_
+#define SOURCE_FUZZ_FUZZER_CONTEXT_H_
+
+#include "source/fuzz/random_generator.h"
+#include "source/opt/function.h"
+
+namespace spvtools {
+namespace fuzz {
+
+// Encapsulates all parameters that control the fuzzing process, such as the
+// source of randomness and the probabilities with which transformations are
+// applied.
+class FuzzerContext {
+ public:
+ // Constructs a fuzzer context with a given random generator and the minimum
+ // value that can be used for fresh ids.
+ FuzzerContext(RandomGenerator* random_generator, uint32_t min_fresh_id);
+
+ ~FuzzerContext();
+
+ // Provides the random generator used to control fuzzing.
+ RandomGenerator* GetRandomGenerator();
+
+ // Yields an id that is guaranteed not to be used in the module being fuzzed,
+ // or to have been issued before.
+ uint32_t GetFreshId();
+
+ private:
+ // The source of randomness.
+ RandomGenerator* random_generator_;
+ // The next fresh id to be issued.
+ uint32_t next_fresh_id_;
+};
+
+} // namespace fuzz
+} // namespace spvtools
+
+#endif // SOURCE_FUZZ_FUZZER_CONTEXT_H_
diff --git a/source/fuzz/fuzzer_pass.cpp b/source/fuzz/fuzzer_pass.cpp
new file mode 100644
index 0000000..823f2e0
--- /dev/null
+++ b/source/fuzz/fuzzer_pass.cpp
@@ -0,0 +1,31 @@
+// 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.
+
+#include "source/fuzz/fuzzer_pass.h"
+
+namespace spvtools {
+namespace fuzz {
+
+FuzzerPass::FuzzerPass(opt::IRContext* ir_context, FactManager* fact_manager,
+ FuzzerContext* fuzzer_context,
+ protobufs::TransformationSequence* transformations)
+ : ir_context_(ir_context),
+ fact_manager_(fact_manager),
+ fuzzer_context_(fuzzer_context),
+ transformations_(transformations) {}
+
+FuzzerPass::~FuzzerPass() = default;
+
+} // namespace fuzz
+} // namespace spvtools
diff --git a/source/fuzz/fuzzer_pass.h b/source/fuzz/fuzzer_pass.h
new file mode 100644
index 0000000..4d0861e
--- /dev/null
+++ b/source/fuzz/fuzzer_pass.h
@@ -0,0 +1,61 @@
+// 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_PASS_H_
+#define SOURCE_FUZZ_FUZZER_PASS_H_
+
+#include "source/fuzz/fact_manager.h"
+#include "source/fuzz/fuzzer_context.h"
+#include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
+
+namespace spvtools {
+namespace fuzz {
+
+// Interface for applying a pass of transformations to a module.
+class FuzzerPass {
+ public:
+ FuzzerPass(opt::IRContext* ir_context, FactManager* fact_manager,
+ FuzzerContext* fuzzer_context,
+ protobufs::TransformationSequence* transformations);
+
+ virtual ~FuzzerPass();
+
+ // Applies the pass to the module |ir_context_|, assuming and updating
+ // facts from |fact_manager_|, and using |fuzzer_context_| to guide the
+ // process. Appends to |transformations_| all transformations that were
+ // applied during the pass.
+ virtual void Apply() = 0;
+
+ protected:
+ opt::IRContext* GetIRContext() const { return ir_context_; }
+
+ FactManager* GetFactManager() const { return fact_manager_; }
+
+ FuzzerContext* GetFuzzerContext() const { return fuzzer_context_; }
+
+ protobufs::TransformationSequence* GetTransformations() const {
+ return transformations_;
+ }
+
+ private:
+ opt::IRContext* ir_context_;
+ FactManager* fact_manager_;
+ FuzzerContext* fuzzer_context_;
+ protobufs::TransformationSequence* transformations_;
+};
+
+} // namespace fuzz
+} // namespace spvtools
+
+#endif // #define SOURCE_FUZZ_FUZZER_PASS_H_
diff --git a/source/fuzz/protobufs/spirvfuzz_protobufs.h b/source/fuzz/protobufs/spirvfuzz_protobufs.h
new file mode 100644
index 0000000..b801626
--- /dev/null
+++ b/source/fuzz/protobufs/spirvfuzz_protobufs.h
@@ -0,0 +1,52 @@
+// 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_SPIRVFUZZ_PROTOBUFS_H_
+#define SOURCE_FUZZ_SPIRVFUZZ_PROTOBUFS_H_
+
+// This header file serves to act as a barrier between the protobuf header
+// files and files that include them. It uses compiler pragmas to disable
+// diagnostics, in order to ignore warnings generated during the processing
+// of these header files without having to compromise on freedom from warnings
+// in the rest of the project.
+
+#if defined(__clang__)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunused-parameter"
+#elif defined(__GNUC__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wconversion"
+#pragma GCC diagnostic ignored "-Wshadow"
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#elif defined(_MSC_VER)
+#pragma warning(push)
+#pragma warning(disable : 4244)
+#endif
+
+// The following should be the only place in the project where protobuf files
+// are directly included. This is so that they can be compiled in a manner
+// where warnings are ignored.
+
+#include "google/protobuf/util/json_util.h"
+#include "source/fuzz/protobufs/spvtoolsfuzz.pb.h"
+
+#if defined(__clang__)
+#pragma clang diagnostic pop
+#elif defined(__GNUC__)
+#pragma GCC diagnostic pop
+#elif defined(_MSC_VER)
+#pragma warning(pop)
+#endif
+
+#endif // SOURCE_FUZZ_SPIRVFUZZ_PROTOBUFS_H_
diff --git a/source/fuzz/protobufs/spvtoolsfuzz.proto b/source/fuzz/protobufs/spvtoolsfuzz.proto
new file mode 100644
index 0000000..e87819a
--- /dev/null
+++ b/source/fuzz/protobufs/spvtoolsfuzz.proto
@@ -0,0 +1,38 @@
+// 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.
+
+// This file is specifically named spvtools_fuzz.proto so that the string
+// 'spvtools_fuzz' appears in the names of global-scope symbols that protoc
+// generates when targeting C++. This is to reduce the potential for name
+// clashes with other globally-scoped symbols.
+
+syntax = "proto3";
+
+package spvtools.fuzz.protobufs;
+
+message FactSequence {
+ repeated Fact fact = 1;
+}
+
+message Fact {
+ // Currently there are no facts.
+}
+
+message TransformationSequence {
+ repeated Transformation transformation = 1;
+}
+
+message Transformation {
+ // Currently there are no transformations.
+}
diff --git a/source/fuzz/pseudo_random_generator.cpp b/source/fuzz/pseudo_random_generator.cpp
new file mode 100644
index 0000000..773b89d
--- /dev/null
+++ b/source/fuzz/pseudo_random_generator.cpp
@@ -0,0 +1,47 @@
+// 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.
+
+#include <cassert>
+
+#include "source/fuzz/pseudo_random_generator.h"
+
+namespace spvtools {
+namespace fuzz {
+
+PseudoRandomGenerator::PseudoRandomGenerator(uint32_t seed) : mt_(seed) {}
+
+PseudoRandomGenerator::~PseudoRandomGenerator() = default;
+
+uint32_t PseudoRandomGenerator::RandomUint32(uint32_t bound) {
+ assert(bound > 0 && "Bound must be positive");
+ return static_cast<uint32_t>(
+ std::uniform_int_distribution<>(0, bound - 1)(mt_));
+}
+
+bool PseudoRandomGenerator::RandomBool() {
+ return static_cast<bool>(std::uniform_int_distribution<>(0, 1)(mt_));
+}
+
+uint32_t PseudoRandomGenerator::RandomPercentage() {
+ // We use 101 because we want a result in the closed interval [0, 100], and
+ // RandomUint32 is not inclusive of its bound.
+ return RandomUint32(101);
+}
+
+double PseudoRandomGenerator::RandomDouble() {
+ return std::uniform_real_distribution<double>(0.0, 1.0)(mt_);
+}
+
+} // namespace fuzz
+} // namespace spvtools
diff --git a/source/fuzz/pseudo_random_generator.h b/source/fuzz/pseudo_random_generator.h
new file mode 100644
index 0000000..d2f5292
--- /dev/null
+++ b/source/fuzz/pseudo_random_generator.h
@@ -0,0 +1,47 @@
+// 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_PSEUDO_RANDOM_GENERATOR_H_
+#define SOURCE_FUZZ_PSEUDO_RANDOM_GENERATOR_H_
+
+#include <random>
+
+#include "source/fuzz/random_generator.h"
+
+namespace spvtools {
+namespace fuzz {
+
+// Generates random data from a pseudo-random number generator.
+class PseudoRandomGenerator : public RandomGenerator {
+ public:
+ explicit PseudoRandomGenerator(uint32_t seed);
+
+ ~PseudoRandomGenerator() override;
+
+ uint32_t RandomUint32(uint32_t bound) override;
+
+ uint32_t RandomPercentage() override;
+
+ bool RandomBool() override;
+
+ double RandomDouble() override;
+
+ private:
+ std::mt19937 mt_;
+};
+
+} // namespace fuzz
+} // namespace spvtools
+
+#endif // SOURCE_FUZZ_PSEUDO_RANDOM_GENERATOR_H_
diff --git a/source/fuzz/random_generator.cpp b/source/fuzz/random_generator.cpp
new file mode 100644
index 0000000..9ec4845
--- /dev/null
+++ b/source/fuzz/random_generator.cpp
@@ -0,0 +1,25 @@
+// 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.
+
+#include "source/fuzz/random_generator.h"
+
+namespace spvtools {
+namespace fuzz {
+
+RandomGenerator::RandomGenerator() = default;
+
+RandomGenerator::~RandomGenerator() = default;
+
+} // namespace fuzz
+} // namespace spvtools
diff --git a/source/fuzz/random_generator.h b/source/fuzz/random_generator.h
new file mode 100644
index 0000000..9c46798
--- /dev/null
+++ b/source/fuzz/random_generator.h
@@ -0,0 +1,45 @@
+// 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_RANDOM_GENERATOR_H_
+#define SOURCE_FUZZ_RANDOM_GENERATOR_H_
+
+#include <stdint.h>
+
+namespace spvtools {
+namespace fuzz {
+
+class RandomGenerator {
+ public:
+ RandomGenerator();
+
+ virtual ~RandomGenerator();
+
+ // Returns a value in the half-open interval [0, bound).
+ virtual uint32_t RandomUint32(uint32_t bound) = 0;
+
+ // Returns a value in the closed interval [0, 100].
+ virtual uint32_t RandomPercentage() = 0;
+
+ // Returns a boolean.
+ virtual bool RandomBool() = 0;
+
+ // Returns a double in the closed interval [0, 1]
+ virtual double RandomDouble() = 0;
+};
+
+} // namespace fuzz
+} // namespace spvtools
+
+#endif // SOURCE_FUZZ_RANDOM_GENERATOR_H_
diff --git a/source/spirv_fuzzer_options.cpp b/source/spirv_fuzzer_options.cpp
new file mode 100644
index 0000000..f6319ca
--- /dev/null
+++ b/source/spirv_fuzzer_options.cpp
@@ -0,0 +1,31 @@
+// 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.
+
+#include "source/spirv_fuzzer_options.h"
+
+spv_fuzzer_options_t::spv_fuzzer_options_t() = default;
+
+SPIRV_TOOLS_EXPORT spv_fuzzer_options spvFuzzerOptionsCreate() {
+ return new spv_fuzzer_options_t();
+}
+
+SPIRV_TOOLS_EXPORT void spvFuzzerOptionsDestroy(spv_fuzzer_options options) {
+ delete options;
+}
+
+SPIRV_TOOLS_EXPORT void spvFuzzerOptionsSetRandomSeed(
+ spv_fuzzer_options options, uint32_t seed) {
+ options->has_random_seed = true;
+ options->random_seed = seed;
+}
diff --git a/source/spirv_fuzzer_options.h b/source/spirv_fuzzer_options.h
new file mode 100644
index 0000000..1193bfd
--- /dev/null
+++ b/source/spirv_fuzzer_options.h
@@ -0,0 +1,33 @@
+// 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_SPIRV_FUZZER_OPTIONS_H_
+#define SOURCE_SPIRV_FUZZER_OPTIONS_H_
+
+#include "spirv-tools/libspirv.h"
+
+#include <string>
+#include <utility>
+
+// Manages command line options passed to the SPIR-V Fuzzer. New struct
+// members may be added for any new option.
+struct spv_fuzzer_options_t {
+ spv_fuzzer_options_t();
+
+ // See spvFuzzerOptionsSetRandomSeed.
+ bool has_random_seed = false;
+ uint32_t random_seed = 0;
+};
+
+#endif // SOURCE_SPIRV_FUZZER_OPTIONS_H_
diff --git a/utils/check_symbol_exports.py b/utils/check_symbol_exports.py
index d4c8579..a8f3785 100755
--- a/utils/check_symbol_exports.py
+++ b/utils/check_symbol_exports.py
@@ -56,6 +56,13 @@
# _ZN : something in a namespace
# _Z[0-9]+spv[A-Z_] : C++ symbol starting with spv[A-Z_]
symbol_ok_pattern = re.compile(r'^(spv[A-Z]|_ZN|_Z[0-9]+spv[A-Z_])')
+
+ # In addition, the following pattern whitelists global functions that are added
+ # by the protobuf compiler:
+ # - AddDescriptors_spvtoolsfuzz_2eproto()
+ # - InitDefaults_spvtoolsfuzz_2eproto()
+ symbol_whitelist_pattern = re.compile(r'_Z[0-9]+(InitDefaults|AddDescriptors)_spvtoolsfuzz_2eprotov')
+
seen = set()
result = 0
for line in command_output(['objdump', '-t', library], '.').split('\n'):
@@ -65,7 +72,7 @@
if symbol not in seen:
seen.add(symbol)
#print("look at '{}'".format(symbol))
- if not symbol_ok_pattern.match(symbol):
+ if not (symbol_whitelist_pattern.match(symbol) or symbol_ok_pattern.match(symbol)):
print('{}: error: Unescaped exported symbol: {}'.format(PROG, symbol))
result = 1
return result