Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

spirv-fuzz: Fuzzer pass to add composite types #3171

Merged
merged 3 commits into from
Feb 4, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions source/fuzz/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ if(SPIRV_BUILD_FUZZER)
fuzzer.h
fuzzer_context.h
fuzzer_pass.h
fuzzer_pass_add_composite_types.h
fuzzer_pass_add_dead_blocks.h
fuzzer_pass_add_dead_breaks.h
fuzzer_pass_add_dead_continues.h
Expand Down Expand Up @@ -107,6 +108,7 @@ if(SPIRV_BUILD_FUZZER)
fuzzer.cpp
fuzzer_context.cpp
fuzzer_pass.cpp
fuzzer_pass_add_composite_types.cpp
fuzzer_pass_add_dead_blocks.cpp
fuzzer_pass_add_dead_breaks.cpp
fuzzer_pass_add_dead_continues.cpp
Expand Down
4 changes: 4 additions & 0 deletions source/fuzz/fuzzer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "fuzzer_pass_adjust_memory_operands_masks.h"
#include "source/fuzz/fact_manager.h"
#include "source/fuzz/fuzzer_context.h"
#include "source/fuzz/fuzzer_pass_add_composite_types.h"
#include "source/fuzz/fuzzer_pass_add_dead_blocks.h"
#include "source/fuzz/fuzzer_pass_add_dead_breaks.h"
#include "source/fuzz/fuzzer_pass_add_dead_continues.h"
Expand Down Expand Up @@ -178,6 +179,9 @@ Fuzzer::FuzzerResultStatus Fuzzer::Run(
// Apply some semantics-preserving passes.
std::vector<std::unique_ptr<FuzzerPass>> passes;
while (passes.empty()) {
MaybeAddPass<FuzzerPassAddCompositeTypes>(&passes, ir_context.get(),
&fact_manager, &fuzzer_context,
transformation_sequence_out);
MaybeAddPass<FuzzerPassAddDeadBlocks>(&passes, ir_context.get(),
&fact_manager, &fuzzer_context,
transformation_sequence_out);
Expand Down
19 changes: 19 additions & 0 deletions source/fuzz/fuzzer_context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,25 @@ namespace {
// Default <minimum, maximum> pairs of probabilities for applying various
// transformations. All values are percentages. Keep them in alphabetical order.

const std::pair<uint32_t, uint32_t> kChanceOfAddingAnotherStructField = {20,
90};
const std::pair<uint32_t, uint32_t> kChanceOfAddingArrayOrStructType = {20, 90};
const std::pair<uint32_t, uint32_t> kChanceOfAddingDeadBlock = {20, 90};
const std::pair<uint32_t, uint32_t> kChanceOfAddingDeadBreak = {5, 80};
const std::pair<uint32_t, uint32_t> kChanceOfAddingDeadContinue = {5, 80};
const std::pair<uint32_t, uint32_t> kChanceOfAddingMatrixType = {20, 70};
const std::pair<uint32_t, uint32_t> kChanceOfAddingNoContractionDecoration = {
5, 70};
const std::pair<uint32_t, uint32_t> kChanceOfAddingVectorType = {20, 70};
const std::pair<uint32_t, uint32_t> kChanceOfAdjustingFunctionControl = {20,
70};
const std::pair<uint32_t, uint32_t> kChanceOfAdjustingLoopControl = {20, 90};
const std::pair<uint32_t, uint32_t> kChanceOfAdjustingMemoryOperandsMask = {20,
90};
const std::pair<uint32_t, uint32_t> kChanceOfAdjustingSelectionControl = {20,
90};
const std::pair<uint32_t, uint32_t> kChanceOfChoosingStructTypeVsArrayType = {
20, 80};
const std::pair<uint32_t, uint32_t> kChanceOfConstructingComposite = {20, 50};
const std::pair<uint32_t, uint32_t> kChanceOfCopyingObject = {20, 50};
const std::pair<uint32_t, uint32_t> kChanceOfDonatingAdditionalModule = {5, 50};
Expand All @@ -51,6 +58,7 @@ const std::pair<uint32_t, uint32_t> kChanceOfSplittingBlock = {40, 95};
const uint32_t kDefaultMaxLoopControlPartialCount = 100;
const uint32_t kDefaultMaxLoopControlPeelCount = 100;
const uint32_t kDefaultMaxLoopLimit = 20;
const uint32_t kDefaultMaxNewArraySizeLimit = 100;

// Default functions for controlling how deep to go during recursive
// generation/transformation. Keep them in alphabetical order.
Expand All @@ -70,14 +78,22 @@ FuzzerContext::FuzzerContext(RandomGenerator* random_generator,
next_fresh_id_(min_fresh_id),
go_deeper_in_constant_obfuscation_(
kDefaultGoDeeperInConstantObfuscation) {
chance_of_adding_another_struct_field_ =
ChooseBetweenMinAndMax(kChanceOfAddingAnotherStructField);
chance_of_adding_array_or_struct_type_ =
ChooseBetweenMinAndMax(kChanceOfAddingArrayOrStructType);
chance_of_adding_dead_block_ =
ChooseBetweenMinAndMax(kChanceOfAddingDeadBlock);
chance_of_adding_dead_break_ =
ChooseBetweenMinAndMax(kChanceOfAddingDeadBreak);
chance_of_adding_dead_continue_ =
ChooseBetweenMinAndMax(kChanceOfAddingDeadContinue);
chance_of_adding_matrix_type_ =
ChooseBetweenMinAndMax(kChanceOfAddingMatrixType);
chance_of_adding_no_contraction_decoration_ =
ChooseBetweenMinAndMax(kChanceOfAddingNoContractionDecoration);
chance_of_adding_vector_type_ =
ChooseBetweenMinAndMax(kChanceOfAddingVectorType);
chance_of_adjusting_function_control_ =
ChooseBetweenMinAndMax(kChanceOfAdjustingFunctionControl);
chance_of_adjusting_loop_control_ =
Expand All @@ -86,6 +102,8 @@ FuzzerContext::FuzzerContext(RandomGenerator* random_generator,
ChooseBetweenMinAndMax(kChanceOfAdjustingMemoryOperandsMask);
chance_of_adjusting_selection_control_ =
ChooseBetweenMinAndMax(kChanceOfAdjustingSelectionControl);
chance_of_choosing_struct_type_vs_array_type_ =
ChooseBetweenMinAndMax(kChanceOfChoosingStructTypeVsArrayType);
chance_of_constructing_composite_ =
ChooseBetweenMinAndMax(kChanceOfConstructingComposite);
chance_of_copying_object_ = ChooseBetweenMinAndMax(kChanceOfCopyingObject);
Expand All @@ -106,6 +124,7 @@ FuzzerContext::FuzzerContext(RandomGenerator* random_generator,
max_loop_control_partial_count_ = kDefaultMaxLoopControlPartialCount;
max_loop_control_peel_count_ = kDefaultMaxLoopControlPeelCount;
max_loop_limit_ = kDefaultMaxLoopLimit;
max_new_array_size_limit_ = kDefaultMaxNewArraySizeLimit;
}

FuzzerContext::~FuzzerContext() = default;
Expand Down
25 changes: 25 additions & 0 deletions source/fuzz/fuzzer_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,14 +58,26 @@ class FuzzerContext {

// Probabilities associated with applying various transformations.
// Keep them in alphabetical order.
uint32_t GetChanceOfAddingAnotherStructField() {
return chance_of_adding_another_struct_field_;
}
uint32_t GetChanceOfAddingArrayOrStructType() {
return chance_of_adding_array_or_struct_type_;
}
uint32_t GetChanceOfAddingDeadBlock() { return chance_of_adding_dead_block_; }
uint32_t GetChanceOfAddingDeadBreak() { return chance_of_adding_dead_break_; }
uint32_t GetChanceOfAddingDeadContinue() {
return chance_of_adding_dead_continue_;
}
uint32_t GetChanceOfAddingMatrixType() {
return chance_of_adding_matrix_type_;
}
uint32_t GetChanceOfAddingNoContractionDecoration() {
return chance_of_adding_no_contraction_decoration_;
}
uint32_t GetChanceOfAddingVectorType() {
return chance_of_adding_vector_type_;
}
uint32_t GetChanceOfAdjustingFunctionControl() {
return chance_of_adjusting_function_control_;
}
Expand All @@ -78,6 +90,9 @@ class FuzzerContext {
uint32_t GetChanceOfAdjustingSelectionControl() {
return chance_of_adjusting_selection_control_;
}
uint32_t GetChanceOfChoosingStructTypeVsArrayType() {
return chance_of_choosing_struct_type_vs_array_type_;
}
uint32_t GetChanceOfConstructingComposite() {
return chance_of_constructing_composite_;
}
Expand Down Expand Up @@ -109,6 +124,10 @@ class FuzzerContext {
uint32_t GetRandomLoopLimit() {
return random_generator_->RandomUint32(max_loop_limit_);
}
uint32_t GetRandomSizeForNewArray() {
// Ensure that the array size is non-zero.
return random_generator_->RandomUint32(max_new_array_size_limit_ - 1) + 1;
}

// Functions to control how deeply to recurse.
// Keep them in alphabetical order.
Expand All @@ -124,14 +143,19 @@ class FuzzerContext {

// Probabilities associated with applying various transformations.
// Keep them in alphabetical order.
uint32_t chance_of_adding_another_struct_field_;
uint32_t chance_of_adding_array_or_struct_type_;
uint32_t chance_of_adding_dead_block_;
uint32_t chance_of_adding_dead_break_;
uint32_t chance_of_adding_dead_continue_;
uint32_t chance_of_adding_matrix_type_;
uint32_t chance_of_adding_no_contraction_decoration_;
uint32_t chance_of_adding_vector_type_;
uint32_t chance_of_adjusting_function_control_;
uint32_t chance_of_adjusting_loop_control_;
uint32_t chance_of_adjusting_memory_operands_mask_;
uint32_t chance_of_adjusting_selection_control_;
uint32_t chance_of_choosing_struct_type_vs_array_type_;
uint32_t chance_of_constructing_composite_;
uint32_t chance_of_copying_object_;
uint32_t chance_of_donating_additional_module_;
Expand All @@ -149,6 +173,7 @@ class FuzzerContext {
uint32_t max_loop_control_partial_count_;
uint32_t max_loop_control_peel_count_;
uint32_t max_loop_limit_;
uint32_t max_new_array_size_limit_;

// Functions to determine with what probability to go deeper when generating
// or mutating constructs recursively.
Expand Down
53 changes: 53 additions & 0 deletions source/fuzz/fuzzer_pass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,11 @@
#include "source/fuzz/transformation_add_constant_scalar.h"
#include "source/fuzz/transformation_add_global_undef.h"
#include "source/fuzz/transformation_add_type_boolean.h"
#include "source/fuzz/transformation_add_type_float.h"
#include "source/fuzz/transformation_add_type_int.h"
#include "source/fuzz/transformation_add_type_matrix.h"
#include "source/fuzz/transformation_add_type_pointer.h"
#include "source/fuzz/transformation_add_type_vector.h"

namespace spvtools {
namespace fuzz {
Expand Down Expand Up @@ -155,6 +158,56 @@ uint32_t FuzzerPass::FindOrCreate32BitIntegerType(bool is_signed) {
return result;
}

uint32_t FuzzerPass::FindOrCreate32BitFloatType() {
opt::analysis::Float float_type(32);
auto existing_id = GetIRContext()->get_type_mgr()->GetId(&float_type);
if (existing_id) {
return existing_id;
}
auto result = GetFuzzerContext()->GetFreshId();
ApplyTransformation(TransformationAddTypeFloat(result, 32));
return result;
}

uint32_t FuzzerPass::FindOrCreateVectorType(uint32_t component_type_id,
uint32_t component_count) {
assert(component_count >= 2 && component_count <= 4 &&
"Precondition: component count must be in range [2, 4].");
opt::analysis::Type* component_type =
GetIRContext()->get_type_mgr()->GetType(component_type_id);
assert(component_type && "Precondition: the component type must exist.");
opt::analysis::Vector vector_type(component_type, component_count);
auto existing_id = GetIRContext()->get_type_mgr()->GetId(&vector_type);
if (existing_id) {
return existing_id;
}
auto result = GetFuzzerContext()->GetFreshId();
ApplyTransformation(
TransformationAddTypeVector(result, component_type_id, component_count));
return result;
}

uint32_t FuzzerPass::FindOrCreateMatrixType(uint32_t column_count,
uint32_t row_count) {
assert(column_count >= 2 && column_count <= 4 &&
"Precondition: column count must be in range [2, 4].");
assert(row_count >= 2 && row_count <= 4 &&
"Precondition: row count must be in range [2, 4].");
uint32_t column_type_id =
FindOrCreateVectorType(FindOrCreate32BitFloatType(), row_count);
opt::analysis::Type* column_type =
GetIRContext()->get_type_mgr()->GetType(column_type_id);
opt::analysis::Matrix matrix_type(column_type, column_count);
auto existing_id = GetIRContext()->get_type_mgr()->GetId(&matrix_type);
if (existing_id) {
return existing_id;
}
auto result = GetFuzzerContext()->GetFreshId();
ApplyTransformation(
TransformationAddTypeMatrix(result, column_type_id, column_count));
return result;
}

uint32_t FuzzerPass::FindOrCreatePointerTo32BitIntegerType(
bool is_signed, SpvStorageClass storage_class) {
auto uint32_type_id = FindOrCreate32BitIntegerType(is_signed);
Expand Down
17 changes: 17 additions & 0 deletions source/fuzz/fuzzer_pass.h
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,23 @@ class FuzzerPass {
// transformation is applied to add it.
uint32_t FindOrCreate32BitIntegerType(bool is_signed);

// Returns the id of an OpTypeFloat instruction, with width 32. If such an
// instruction does not exist, a transformation is applied to add it.
uint32_t FindOrCreate32BitFloatType();

// Returns the id of an OpTypeVector instruction, with |component_type_id|
// (which must already exist) as its base type, and |component_count|
// elements (which must be in the range [2, 4]). If such an instruction does
// not exist, a transformation is applied to add it.
uint32_t FindOrCreateVectorType(uint32_t component_type_id,
uint32_t component_count);

// Returns the id of an OpTypeMatrix instruction, with |column_count| columns
// and |row_count| rows (each of which must be in the range [2, 4]). If the
// float and vector types required to build this matrix type or the matrix
// type itself do not exist, transformations are applied to add them.
uint32_t FindOrCreateMatrixType(uint32_t column_count, uint32_t row_count);

// Returns the id of an OpTypePointer instruction, with a 32-bit integer base
// type of signedness specified by |is_signed|. If the pointer type or
// required integer base type do not exist, transformations are applied to add
Expand Down
Loading