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.
This commit is contained in:
Alastair Donaldson 2019-05-27 14:34:55 +01:00 committed by GitHub
parent 42abaa099a
commit fe9f870130
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 915 additions and 1 deletions

View File

@ -370,6 +370,8 @@ typedef struct spv_optimizer_options_t spv_optimizer_options_t;
typedef struct spv_reducer_options_t spv_reducer_options_t; typedef struct spv_reducer_options_t spv_reducer_options_t;
typedef struct spv_fuzzer_options_t spv_fuzzer_options_t;
// Type Definitions // Type Definitions
typedef spv_const_binary_t* spv_const_binary; typedef spv_const_binary_t* spv_const_binary;
@ -385,6 +387,8 @@ typedef spv_optimizer_options_t* spv_optimizer_options;
typedef const spv_optimizer_options_t* spv_const_optimizer_options; typedef const spv_optimizer_options_t* spv_const_optimizer_options;
typedef spv_reducer_options_t* spv_reducer_options; typedef spv_reducer_options_t* spv_reducer_options;
typedef const spv_reducer_options_t* spv_const_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 // Platform API
@ -590,6 +594,19 @@ SPIRV_TOOLS_EXPORT void spvReducerOptionsSetStepLimit(
SPIRV_TOOLS_EXPORT void spvReducerOptionsSetFailOnValidationError( SPIRV_TOOLS_EXPORT void spvReducerOptionsSetFailOnValidationError(
spv_reducer_options options, bool fail_on_validation_error); 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 // Encodes the given SPIR-V assembly text to its binary representation. The
// length parameter specifies the number of bytes for text. Encoded binary will // length parameter specifies the number of bytes for text. Encoded binary will
// be stored into *binary. Any error will be written into *diagnostic if // be stored into *binary. Any error will be written into *diagnostic if

View File

@ -191,6 +191,26 @@ class ReducerOptions {
spv_reducer_options options_; 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 // C++ interface for SPIRV-Tools functionalities. It wraps the context
// (including target environment and the corresponding SPIR-V grammar) and // (including target environment and the corresponding SPIR-V grammar) and
// provides methods for assembling, disassembling, and validating. // provides methods for assembling, disassembling, and validating.

View File

@ -198,6 +198,7 @@ set_source_files_properties(
add_subdirectory(opt) add_subdirectory(opt)
add_subdirectory(reduce) add_subdirectory(reduce)
add_subdirectory(fuzz)
add_subdirectory(link) add_subdirectory(link)
set(SPIRV_SOURCES set(SPIRV_SOURCES
@ -233,6 +234,7 @@ set(SPIRV_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/spirv_constant.h ${CMAKE_CURRENT_SOURCE_DIR}/spirv_constant.h
${CMAKE_CURRENT_SOURCE_DIR}/spirv_definition.h ${CMAKE_CURRENT_SOURCE_DIR}/spirv_definition.h
${CMAKE_CURRENT_SOURCE_DIR}/spirv_endian.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_optimizer_options.h
${CMAKE_CURRENT_SOURCE_DIR}/spirv_reducer_options.h ${CMAKE_CURRENT_SOURCE_DIR}/spirv_reducer_options.h
${CMAKE_CURRENT_SOURCE_DIR}/spirv_target_env.h ${CMAKE_CURRENT_SOURCE_DIR}/spirv_target_env.h
@ -260,6 +262,7 @@ set(SPIRV_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/print.cpp ${CMAKE_CURRENT_SOURCE_DIR}/print.cpp
${CMAKE_CURRENT_SOURCE_DIR}/software_version.cpp ${CMAKE_CURRENT_SOURCE_DIR}/software_version.cpp
${CMAKE_CURRENT_SOURCE_DIR}/spirv_endian.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_optimizer_options.cpp
${CMAKE_CURRENT_SOURCE_DIR}/spirv_reducer_options.cpp ${CMAKE_CURRENT_SOURCE_DIR}/spirv_reducer_options.cpp
${CMAKE_CURRENT_SOURCE_DIR}/spirv_target_env.cpp ${CMAKE_CURRENT_SOURCE_DIR}/spirv_target_env.cpp

View File

@ -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)

View File

@ -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

View File

@ -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_

109
source/fuzz/fuzzer.cpp Normal file
View File

@ -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

74
source/fuzz/fuzzer.h Normal file
View File

@ -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_

View File

@ -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

View File

@ -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_

View File

@ -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

61
source/fuzz/fuzzer_pass.h Normal file
View File

@ -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_

View File

@ -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_

View File

@ -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.
}

View File

@ -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

View File

@ -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_

View File

@ -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

View File

@ -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_

View File

@ -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;
}

View File

@ -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_

View File

@ -56,6 +56,13 @@ def check_library(library):
# _ZN : something in a namespace # _ZN : something in a namespace
# _Z[0-9]+spv[A-Z_] : C++ symbol starting with spv[A-Z_] # _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_])') 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() seen = set()
result = 0 result = 0
for line in command_output(['objdump', '-t', library], '.').split('\n'): for line in command_output(['objdump', '-t', library], '.').split('\n'):
@ -65,7 +72,7 @@ def check_library(library):
if symbol not in seen: if symbol not in seen:
seen.add(symbol) seen.add(symbol)
#print("look at '{}'".format(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)) print('{}: error: Unescaped exported symbol: {}'.format(PROG, symbol))
result = 1 result = 1
return result return result