aboutsummaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
Diffstat (limited to 'source')
-rw-r--r--source/fuzz/CMakeLists.txt2
-rw-r--r--source/fuzz/fuzzer.cpp11
-rw-r--r--source/fuzz/fuzzer_pass.cpp29
-rw-r--r--source/fuzz/fuzzer_pass.h8
-rw-r--r--source/fuzz/fuzzer_pass_add_dead_blocks.cpp9
-rw-r--r--source/fuzz/fuzzer_pass_add_dead_breaks.cpp8
-rw-r--r--source/fuzz/fuzzer_pass_add_dead_continues.cpp7
-rw-r--r--source/fuzz/fuzzer_pass_add_useful_constructs.cpp222
-rw-r--r--source/fuzz/fuzzer_pass_add_useful_constructs.h46
-rw-r--r--source/fuzz/fuzzer_pass_obfuscate_constants.cpp86
-rw-r--r--source/fuzz/fuzzer_pass_obfuscate_constants.h5
-rw-r--r--source/fuzz/fuzzer_util.h1
12 files changed, 131 insertions, 303 deletions
diff --git a/source/fuzz/CMakeLists.txt b/source/fuzz/CMakeLists.txt
index 0d4e4ea8..65829274 100644
--- a/source/fuzz/CMakeLists.txt
+++ b/source/fuzz/CMakeLists.txt
@@ -49,7 +49,6 @@ if(SPIRV_BUILD_FUZZER)
fuzzer_pass_add_local_variables.h
fuzzer_pass_add_no_contraction_decorations.h
fuzzer_pass_add_stores.h
- fuzzer_pass_add_useful_constructs.h
fuzzer_pass_adjust_branch_weights.h
fuzzer_pass_adjust_function_controls.h
fuzzer_pass_adjust_loop_controls.h
@@ -146,7 +145,6 @@ if(SPIRV_BUILD_FUZZER)
fuzzer_pass_add_local_variables.cpp
fuzzer_pass_add_no_contraction_decorations.cpp
fuzzer_pass_add_stores.cpp
- fuzzer_pass_add_useful_constructs.cpp
fuzzer_pass_adjust_branch_weights.cpp
fuzzer_pass_adjust_function_controls.cpp
fuzzer_pass_adjust_loop_controls.cpp
diff --git a/source/fuzz/fuzzer.cpp b/source/fuzz/fuzzer.cpp
index d0732541..3343abc7 100644
--- a/source/fuzz/fuzzer.cpp
+++ b/source/fuzz/fuzzer.cpp
@@ -33,7 +33,6 @@
#include "source/fuzz/fuzzer_pass_add_local_variables.h"
#include "source/fuzz/fuzzer_pass_add_no_contraction_decorations.h"
#include "source/fuzz/fuzzer_pass_add_stores.h"
-#include "source/fuzz/fuzzer_pass_add_useful_constructs.h"
#include "source/fuzz/fuzzer_pass_adjust_branch_weights.h"
#include "source/fuzz/fuzzer_pass_adjust_function_controls.h"
#include "source/fuzz/fuzzer_pass_adjust_loop_controls.h"
@@ -187,16 +186,6 @@ Fuzzer::FuzzerResultStatus Fuzzer::Run(
TransformationContext transformation_context(&fact_manager,
impl_->validator_options);
- // Add some essential ingredients to the module if they are not already
- // present, such as boolean constants.
- FuzzerPassAddUsefulConstructs add_useful_constructs(
- ir_context.get(), &transformation_context, &fuzzer_context,
- transformation_sequence_out);
- if (!impl_->ApplyPassAndCheckValidity(&add_useful_constructs, *ir_context,
- tools)) {
- return Fuzzer::FuzzerResultStatus::kFuzzerPassLedToInvalidModule;
- }
-
// Apply some semantics-preserving passes.
std::vector<std::unique_ptr<FuzzerPass>> passes;
while (passes.empty()) {
diff --git a/source/fuzz/fuzzer_pass.cpp b/source/fuzz/fuzzer_pass.cpp
index dbe51433..cd94e4e9 100644
--- a/source/fuzz/fuzzer_pass.cpp
+++ b/source/fuzz/fuzzer_pass.cpp
@@ -319,6 +319,35 @@ uint32_t FuzzerPass::FindOrCreateBoolConstant(bool value) {
return result;
}
+uint32_t FuzzerPass::FindOrCreateConstant(const std::vector<uint32_t>& words,
+ uint32_t type_id) {
+ assert(type_id && "Constant's type id can't be 0.");
+
+ const auto* type = GetIRContext()->get_type_mgr()->GetType(type_id);
+ assert(type && "Type does not exist.");
+
+ if (type->AsBool()) {
+ assert(words.size() == 1);
+ return FindOrCreateBoolConstant(words[0]);
+ } else if (const auto* integer = type->AsInteger()) {
+ assert(integer->width() == 32 && words.size() == 1 &&
+ "Integer must have 32-bit width");
+ return FindOrCreate32BitIntegerConstant(words[0], integer->IsSigned());
+ } else if (const auto* floating = type->AsFloat()) {
+ // Assertions are not evaluated in release builds so |floating|
+ // variable will be unused.
+ (void)floating;
+ assert(floating->width() == 32 && words.size() == 1 &&
+ "Floating point number must have 32-bit width");
+ return FindOrCreate32BitFloatConstant(words[0]);
+ }
+
+ // This assertion will fail in debug build but not in release build
+ // so we return 0 to make compiler happy.
+ assert(false && "Constant type is not supported");
+ return 0;
+}
+
uint32_t FuzzerPass::FindOrCreateGlobalUndef(uint32_t type_id) {
for (auto& inst : GetIRContext()->types_values()) {
if (inst.opcode() == SpvOpUndef && inst.type_id() == type_id) {
diff --git a/source/fuzz/fuzzer_pass.h b/source/fuzz/fuzzer_pass.h
index 67f0f46b..800b8886 100644
--- a/source/fuzz/fuzzer_pass.h
+++ b/source/fuzz/fuzzer_pass.h
@@ -164,6 +164,14 @@ class FuzzerPass {
// type do not exist, transformations are applied to add them.
uint32_t FindOrCreateBoolConstant(bool value);
+ // Returns the id of an OpConstant instruction of type with |type_id|
+ // that consists of |words|. If that instruction doesn't exist,
+ // transformations are applied to add it. |type_id| must be a valid
+ // result id of either scalar or boolean OpType* instruction that exists
+ // in the module.
+ uint32_t FindOrCreateConstant(const std::vector<uint32_t>& words,
+ uint32_t type_id);
+
// Returns the result id of an instruction of the form:
// %id = OpUndef %|type_id|
// If no such instruction exists, a transformation is applied to add it.
diff --git a/source/fuzz/fuzzer_pass_add_dead_blocks.cpp b/source/fuzz/fuzzer_pass_add_dead_blocks.cpp
index 4e9db1f3..30a41454 100644
--- a/source/fuzz/fuzzer_pass_add_dead_blocks.cpp
+++ b/source/fuzz/fuzzer_pass_add_dead_blocks.cpp
@@ -41,6 +41,12 @@ void FuzzerPassAddDeadBlocks::Apply() {
GetFuzzerContext()->GetChanceOfAddingDeadBlock())) {
continue;
}
+
+ // Make sure the module contains a boolean constant equal to
+ // |condition_value|.
+ bool condition_value = GetFuzzerContext()->ChooseEven();
+ FindOrCreateBoolConstant(condition_value);
+
// We speculatively create a transformation, and then apply it (below) if
// it turns out to be applicable. This avoids duplicating the logic for
// applicability checking.
@@ -48,8 +54,7 @@ void FuzzerPassAddDeadBlocks::Apply() {
// It means that fresh ids for transformations that turn out not to be
// applicable end up being unused.
candidate_transformations.emplace_back(TransformationAddDeadBlock(
- GetFuzzerContext()->GetFreshId(), block.id(),
- GetFuzzerContext()->ChooseEven()));
+ GetFuzzerContext()->GetFreshId(), block.id(), condition_value));
}
}
// Apply all those transformations that are in fact applicable.
diff --git a/source/fuzz/fuzzer_pass_add_dead_breaks.cpp b/source/fuzz/fuzzer_pass_add_dead_breaks.cpp
index 6b171dcd..f3900aa6 100644
--- a/source/fuzz/fuzzer_pass_add_dead_breaks.cpp
+++ b/source/fuzz/fuzzer_pass_add_dead_breaks.cpp
@@ -77,9 +77,13 @@ void FuzzerPassAddDeadBreaks::Apply() {
});
}
+ // Make sure the module has a required boolean constant to be used in
+ // OpBranchConditional instruction.
+ auto break_condition = GetFuzzerContext()->ChooseEven();
+ FindOrCreateBoolConstant(break_condition);
+
auto candidate_transformation = TransformationAddDeadBreak(
- block.id(), merge_block->id(), GetFuzzerContext()->ChooseEven(),
- std::move(phi_ids));
+ block.id(), merge_block->id(), break_condition, std::move(phi_ids));
if (candidate_transformation.IsApplicable(
GetIRContext(), *GetTransformationContext())) {
// Only consider a transformation as a candidate if it is applicable.
diff --git a/source/fuzz/fuzzer_pass_add_dead_continues.cpp b/source/fuzz/fuzzer_pass_add_dead_continues.cpp
index b8f07fbe..56a7fd17 100644
--- a/source/fuzz/fuzzer_pass_add_dead_continues.cpp
+++ b/source/fuzz/fuzzer_pass_add_dead_continues.cpp
@@ -68,11 +68,16 @@ void FuzzerPassAddDeadContinues::Apply() {
});
}
+ // Make sure the module contains a boolean constant equal to
+ // |condition_value|.
+ bool condition_value = GetFuzzerContext()->ChooseEven();
+ FindOrCreateBoolConstant(condition_value);
+
// Make a transformation to add a dead continue from this node; if the
// node turns out to be inappropriate (e.g. by not being in a loop) the
// precondition for the transformation will fail and it will be ignored.
auto candidate_transformation = TransformationAddDeadContinue(
- block.id(), GetFuzzerContext()->ChooseEven(), std::move(phi_ids));
+ block.id(), condition_value, std::move(phi_ids));
// Probabilistically decide whether to apply the transformation in the
// case that it is applicable.
if (candidate_transformation.IsApplicable(GetIRContext(),
diff --git a/source/fuzz/fuzzer_pass_add_useful_constructs.cpp b/source/fuzz/fuzzer_pass_add_useful_constructs.cpp
deleted file mode 100644
index a267612b..00000000
--- a/source/fuzz/fuzzer_pass_add_useful_constructs.cpp
+++ /dev/null
@@ -1,222 +0,0 @@
-// 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_add_useful_constructs.h"
-
-#include "source/fuzz/transformation_add_constant_boolean.h"
-#include "source/fuzz/transformation_add_constant_scalar.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_pointer.h"
-
-namespace spvtools {
-namespace fuzz {
-
-FuzzerPassAddUsefulConstructs::FuzzerPassAddUsefulConstructs(
- opt::IRContext* ir_context, TransformationContext* transformation_context,
- FuzzerContext* fuzzer_context,
- protobufs::TransformationSequence* transformations)
- : FuzzerPass(ir_context, transformation_context, fuzzer_context,
- transformations) {}
-
-FuzzerPassAddUsefulConstructs::~FuzzerPassAddUsefulConstructs() = default;
-
-void FuzzerPassAddUsefulConstructs::MaybeAddIntConstant(
- uint32_t width, bool is_signed, std::vector<uint32_t> data) const {
- opt::analysis::Integer temp_int_type(width, is_signed);
- assert(GetIRContext()->get_type_mgr()->GetId(&temp_int_type) &&
- "int type should already be registered.");
- auto registered_int_type = GetIRContext()
- ->get_type_mgr()
- ->GetRegisteredType(&temp_int_type)
- ->AsInteger();
- auto int_type_id = GetIRContext()->get_type_mgr()->GetId(registered_int_type);
- assert(int_type_id &&
- "The relevant int type should have been added to the module already.");
- opt::analysis::IntConstant int_constant(registered_int_type, data);
- if (!GetIRContext()->get_constant_mgr()->FindConstant(&int_constant)) {
- TransformationAddConstantScalar add_constant_int =
- TransformationAddConstantScalar(GetFuzzerContext()->GetFreshId(),
- int_type_id, data);
- assert(add_constant_int.IsApplicable(GetIRContext(),
- *GetTransformationContext()) &&
- "Should be applicable by construction.");
- add_constant_int.Apply(GetIRContext(), GetTransformationContext());
- *GetTransformations()->add_transformation() = add_constant_int.ToMessage();
- }
-}
-
-void FuzzerPassAddUsefulConstructs::MaybeAddFloatConstant(
- uint32_t width, std::vector<uint32_t> data) const {
- opt::analysis::Float temp_float_type(width);
- assert(GetIRContext()->get_type_mgr()->GetId(&temp_float_type) &&
- "float type should already be registered.");
- auto registered_float_type = GetIRContext()
- ->get_type_mgr()
- ->GetRegisteredType(&temp_float_type)
- ->AsFloat();
- auto float_type_id =
- GetIRContext()->get_type_mgr()->GetId(registered_float_type);
- assert(
- float_type_id &&
- "The relevant float type should have been added to the module already.");
- opt::analysis::FloatConstant float_constant(registered_float_type, data);
- if (!GetIRContext()->get_constant_mgr()->FindConstant(&float_constant)) {
- TransformationAddConstantScalar add_constant_float =
- TransformationAddConstantScalar(GetFuzzerContext()->GetFreshId(),
- float_type_id, data);
- assert(add_constant_float.IsApplicable(GetIRContext(),
- *GetTransformationContext()) &&
- "Should be applicable by construction.");
- add_constant_float.Apply(GetIRContext(), GetTransformationContext());
- *GetTransformations()->add_transformation() =
- add_constant_float.ToMessage();
- }
-}
-
-void FuzzerPassAddUsefulConstructs::Apply() {
- {
- // Add boolean type if not present.
- opt::analysis::Bool temp_bool_type;
- if (!GetIRContext()->get_type_mgr()->GetId(&temp_bool_type)) {
- auto add_type_boolean =
- TransformationAddTypeBoolean(GetFuzzerContext()->GetFreshId());
- assert(add_type_boolean.IsApplicable(GetIRContext(),
- *GetTransformationContext()) &&
- "Should be applicable by construction.");
- add_type_boolean.Apply(GetIRContext(), GetTransformationContext());
- *GetTransformations()->add_transformation() =
- add_type_boolean.ToMessage();
- }
- }
-
- {
- // Add signed and unsigned 32-bit integer types if not present.
- for (auto is_signed : {true, false}) {
- opt::analysis::Integer temp_int_type(32, is_signed);
- if (!GetIRContext()->get_type_mgr()->GetId(&temp_int_type)) {
- TransformationAddTypeInt add_type_int = TransformationAddTypeInt(
- GetFuzzerContext()->GetFreshId(), 32, is_signed);
- assert(add_type_int.IsApplicable(GetIRContext(),
- *GetTransformationContext()) &&
- "Should be applicable by construction.");
- add_type_int.Apply(GetIRContext(), GetTransformationContext());
- *GetTransformations()->add_transformation() = add_type_int.ToMessage();
- }
- }
- }
-
- {
- // Add 32-bit float type if not present.
- opt::analysis::Float temp_float_type(32);
- if (!GetIRContext()->get_type_mgr()->GetId(&temp_float_type)) {
- TransformationAddTypeFloat add_type_float =
- TransformationAddTypeFloat(GetFuzzerContext()->GetFreshId(), 32);
- assert(add_type_float.IsApplicable(GetIRContext(),
- *GetTransformationContext()) &&
- "Should be applicable by construction.");
- add_type_float.Apply(GetIRContext(), GetTransformationContext());
- *GetTransformations()->add_transformation() = add_type_float.ToMessage();
- }
- }
-
- // Add boolean constants true and false if not present.
- opt::analysis::Bool temp_bool_type;
- auto bool_type = GetIRContext()
- ->get_type_mgr()
- ->GetRegisteredType(&temp_bool_type)
- ->AsBool();
- for (auto boolean_value : {true, false}) {
- // Add OpConstantTrue/False if not already there.
- opt::analysis::BoolConstant bool_constant(bool_type, boolean_value);
- if (!GetIRContext()->get_constant_mgr()->FindConstant(&bool_constant)) {
- TransformationAddConstantBoolean add_constant_boolean(
- GetFuzzerContext()->GetFreshId(), boolean_value);
- assert(add_constant_boolean.IsApplicable(GetIRContext(),
- *GetTransformationContext()) &&
- "Should be applicable by construction.");
- add_constant_boolean.Apply(GetIRContext(), GetTransformationContext());
- *GetTransformations()->add_transformation() =
- add_constant_boolean.ToMessage();
- }
- }
-
- // Add signed and unsigned 32-bit integer constants 0 and 1 if not present.
- for (auto is_signed : {true, false}) {
- for (auto value : {0u, 1u}) {
- MaybeAddIntConstant(32, is_signed, {value});
- }
- }
-
- // Add 32-bit float constants 0.0 and 1.0 if not present.
- uint32_t uint_data[2];
- float float_data[2] = {0.0, 1.0};
- memcpy(uint_data, float_data, sizeof(float_data));
- for (unsigned int& datum : uint_data) {
- MaybeAddFloatConstant(32, {datum});
- }
-
- // For every known-to-be-constant uniform, make sure we have instructions
- // declaring:
- // - a pointer type with uniform storage class, whose pointee type is the type
- // of the element
- // - a signed integer constant for each index required to access the element
- // - a constant for the constant value itself
- for (auto& fact_and_type_id : GetTransformationContext()
- ->GetFactManager()
- ->GetConstantUniformFactsAndTypes()) {
- uint32_t element_type_id = fact_and_type_id.second;
- assert(element_type_id);
- auto element_type =
- GetIRContext()->get_type_mgr()->GetType(element_type_id);
- assert(element_type &&
- "If the constant uniform fact is well-formed, the module must "
- "already have a declaration of the type for the uniform element.");
- opt::analysis::Pointer uniform_pointer(element_type,
- SpvStorageClassUniform);
- if (!GetIRContext()->get_type_mgr()->GetId(&uniform_pointer)) {
- auto add_pointer =
- TransformationAddTypePointer(GetFuzzerContext()->GetFreshId(),
- SpvStorageClassUniform, element_type_id);
- assert(add_pointer.IsApplicable(GetIRContext(),
- *GetTransformationContext()) &&
- "Should be applicable by construction.");
- add_pointer.Apply(GetIRContext(), GetTransformationContext());
- *GetTransformations()->add_transformation() = add_pointer.ToMessage();
- }
- std::vector<uint32_t> words;
- for (auto word : fact_and_type_id.first.constant_word()) {
- words.push_back(word);
- }
- // We get the element type again as the type manager may have been
- // invalidated since we last retrieved it.
- element_type = GetIRContext()->get_type_mgr()->GetType(element_type_id);
- if (element_type->AsInteger()) {
- MaybeAddIntConstant(element_type->AsInteger()->width(),
- element_type->AsInteger()->IsSigned(), words);
- } else {
- assert(element_type->AsFloat() &&
- "Known uniform values must be integer or floating-point.");
- MaybeAddFloatConstant(element_type->AsFloat()->width(), words);
- }
- for (auto index :
- fact_and_type_id.first.uniform_buffer_element_descriptor().index()) {
- MaybeAddIntConstant(32, true, {index});
- }
- }
-}
-
-} // namespace fuzz
-} // namespace spvtools
diff --git a/source/fuzz/fuzzer_pass_add_useful_constructs.h b/source/fuzz/fuzzer_pass_add_useful_constructs.h
deleted file mode 100644
index 17e87a82..00000000
--- a/source/fuzz/fuzzer_pass_add_useful_constructs.h
+++ /dev/null
@@ -1,46 +0,0 @@
-// 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_ADD_USEFUL_CONSTRUCTS_
-#define SOURCE_FUZZ_FUZZER_PASS_ADD_USEFUL_CONSTRUCTS_
-
-#include "source/fuzz/fuzzer_pass.h"
-
-namespace spvtools {
-namespace fuzz {
-
-// An initial pass for adding useful ingredients to the module, such as boolean
-// constants, if they are not present.
-class FuzzerPassAddUsefulConstructs : public FuzzerPass {
- public:
- FuzzerPassAddUsefulConstructs(
- opt::IRContext* ir_context, TransformationContext* transformation_context,
- FuzzerContext* fuzzer_context,
- protobufs::TransformationSequence* transformations);
-
- ~FuzzerPassAddUsefulConstructs() override;
-
- void Apply() override;
-
- private:
- void MaybeAddIntConstant(uint32_t width, bool is_signed,
- std::vector<uint32_t> data) const;
-
- void MaybeAddFloatConstant(uint32_t width, std::vector<uint32_t> data) const;
-};
-
-} // namespace fuzz
-} // namespace spvtools
-
-#endif // SOURCE_FUZZ_FUZZER_PASS_ADD_USEFUL_CONSTRUCTS_
diff --git a/source/fuzz/fuzzer_pass_obfuscate_constants.cpp b/source/fuzz/fuzzer_pass_obfuscate_constants.cpp
index 4ced507f..543c0d74 100644
--- a/source/fuzz/fuzzer_pass_obfuscate_constants.cpp
+++ b/source/fuzz/fuzzer_pass_obfuscate_constants.cpp
@@ -14,11 +14,14 @@
#include "source/fuzz/fuzzer_pass_obfuscate_constants.h"
+#include <algorithm>
#include <cmath>
+#include "source/fuzz/fuzzer_util.h"
#include "source/fuzz/instruction_descriptor.h"
#include "source/fuzz/transformation_replace_boolean_constant_with_constant_binary.h"
#include "source/fuzz/transformation_replace_constant_with_uniform.h"
+#include "source/fuzz/uniform_buffer_element_descriptor.h"
#include "source/opt/ir_context.h"
namespace spvtools {
@@ -240,6 +243,29 @@ void FuzzerPassObfuscateConstants::
first_constant_is_larger);
}
+std::vector<std::vector<uint32_t>>
+FuzzerPassObfuscateConstants::GetConstantWordsFromUniformsForType(
+ uint32_t type_id) {
+ assert(type_id && "Type id can't be 0");
+ std::vector<std::vector<uint32_t>> result;
+
+ for (const auto& facts_and_types : GetTransformationContext()
+ ->GetFactManager()
+ ->GetConstantUniformFactsAndTypes()) {
+ if (facts_and_types.second != type_id) {
+ continue;
+ }
+
+ std::vector<uint32_t> words(facts_and_types.first.constant_word().begin(),
+ facts_and_types.first.constant_word().end());
+ if (std::find(result.begin(), result.end(), words) == result.end()) {
+ result.push_back(std::move(words));
+ }
+ }
+
+ return result;
+}
+
void FuzzerPassObfuscateConstants::ObfuscateBoolConstant(
uint32_t depth, const protobufs::IdUseDescriptor& constant_use) {
// We want to replace the boolean constant use with a binary expression over
@@ -258,11 +284,9 @@ void FuzzerPassObfuscateConstants::ObfuscateBoolConstant(
auto chosen_type_id =
available_types_with_uniforms[GetFuzzerContext()->RandomIndex(
available_types_with_uniforms)];
- auto available_constants = GetTransformationContext()
- ->GetFactManager()
- ->GetConstantsAvailableFromUniformsForType(
- GetIRContext(), chosen_type_id);
- if (available_constants.size() == 1) {
+ auto available_constant_words =
+ GetConstantWordsFromUniformsForType(chosen_type_id);
+ if (available_constant_words.size() == 1) {
// TODO(afd): for now we only obfuscate a boolean if there are at least
// two constants available from uniforms, so that we can do a
// comparison between them. It would be good to be able to do the
@@ -271,18 +295,25 @@ void FuzzerPassObfuscateConstants::ObfuscateBoolConstant(
return;
}
+ assert(!available_constant_words.empty() &&
+ "There exists a fact but no constants - impossible");
+
// We know we have at least two known-to-be-constant uniforms of the chosen
// type. Pick one of them at random.
- auto constant_index_1 = GetFuzzerContext()->RandomIndex(available_constants);
+ auto constant_index_1 =
+ GetFuzzerContext()->RandomIndex(available_constant_words);
uint32_t constant_index_2;
// Now choose another one distinct from the first one.
do {
- constant_index_2 = GetFuzzerContext()->RandomIndex(available_constants);
+ constant_index_2 =
+ GetFuzzerContext()->RandomIndex(available_constant_words);
} while (constant_index_1 == constant_index_2);
- auto constant_id_1 = available_constants[constant_index_1];
- auto constant_id_2 = available_constants[constant_index_2];
+ auto constant_id_1 = FindOrCreateConstant(
+ available_constant_words[constant_index_1], chosen_type_id);
+ auto constant_id_2 = FindOrCreateConstant(
+ available_constant_words[constant_index_2], chosen_type_id);
assert(constant_id_1 != 0 && constant_id_2 != 0 &&
"We should not find an available constant with an id of 0.");
@@ -324,18 +355,39 @@ void FuzzerPassObfuscateConstants::ObfuscateScalarConstant(
}
// Choose a random available uniform known to be equal to the constant.
- protobufs::UniformBufferElementDescriptor uniform_descriptor =
+ const auto& uniform_descriptor =
uniform_descriptors[GetFuzzerContext()->RandomIndex(uniform_descriptors)];
+
+ // Make sure the module has OpConstant instructions for each index used to
+ // access a uniform.
+ for (auto index : uniform_descriptor.index()) {
+ FindOrCreate32BitIntegerConstant(index, true);
+ }
+
+ // Make sure the module has OpTypePointer that points to the element type of
+ // the uniform.
+ const auto* uniform_variable_instr =
+ FindUniformVariable(uniform_descriptor, GetIRContext(), true);
+ assert(uniform_variable_instr &&
+ "Uniform variable does not exist or not unique.");
+
+ const auto* uniform_variable_type_intr =
+ GetIRContext()->get_def_use_mgr()->GetDef(
+ uniform_variable_instr->type_id());
+ assert(uniform_variable_type_intr && "Uniform variable has invalid type");
+
+ auto element_type_id = fuzzerutil::WalkCompositeTypeIndices(
+ GetIRContext(), uniform_variable_type_intr->GetSingleWordInOperand(1),
+ uniform_descriptor.index());
+ assert(element_type_id && "Type of uniform variable is invalid");
+
+ FindOrCreatePointerType(element_type_id, SpvStorageClassUniform);
+
// Create, apply and record a transformation to replace the constant use with
// the result of a load from the chosen uniform.
- auto transformation = TransformationReplaceConstantWithUniform(
+ ApplyTransformation(TransformationReplaceConstantWithUniform(
constant_use, uniform_descriptor, GetFuzzerContext()->GetFreshId(),
- GetFuzzerContext()->GetFreshId());
- // Transformation should be applicable by construction.
- assert(
- transformation.IsApplicable(GetIRContext(), *GetTransformationContext()));
- transformation.Apply(GetIRContext(), GetTransformationContext());
- *GetTransformations()->add_transformation() = transformation.ToMessage();
+ GetFuzzerContext()->GetFreshId()));
}
void FuzzerPassObfuscateConstants::ObfuscateConstant(
diff --git a/source/fuzz/fuzzer_pass_obfuscate_constants.h b/source/fuzz/fuzzer_pass_obfuscate_constants.h
index 7755d211..52d8efe5 100644
--- a/source/fuzz/fuzzer_pass_obfuscate_constants.h
+++ b/source/fuzz/fuzzer_pass_obfuscate_constants.h
@@ -99,6 +99,11 @@ class FuzzerPassObfuscateConstants : public FuzzerPass {
uint32_t base_instruction_result_id,
const std::map<SpvOp, uint32_t>& skipped_opcode_count,
std::vector<protobufs::IdUseDescriptor>* constant_uses);
+
+ // Returns a vector of unique words that denote constants. Every such constant
+ // is used in |FactConstantUniform| and has type with id equal to |type_id|.
+ std::vector<std::vector<uint32_t>> GetConstantWordsFromUniformsForType(
+ uint32_t type_id);
};
} // namespace fuzz
diff --git a/source/fuzz/fuzzer_util.h b/source/fuzz/fuzzer_util.h
index 886029ac..bccd1d01 100644
--- a/source/fuzz/fuzzer_util.h
+++ b/source/fuzz/fuzzer_util.h
@@ -18,6 +18,7 @@
#include <vector>
#include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
+#include "source/fuzz/transformation_context.h"
#include "source/opt/basic_block.h"
#include "source/opt/instruction.h"
#include "source/opt/ir_context.h"