Warn when input facts are invalid. (#2699)

Fixes #2621.

Instead of aborting when an invalid input fact is provided, the tool
now warns about the invalid fact and then ignores it.  This is
convenient for example if facts are specified about uniforms with
descriptor sets and bindings that happen to not be present in the
input binary.
This commit is contained in:
Alastair Donaldson 2019-06-26 16:40:19 +01:00 committed by GitHub
parent 88183041d5
commit 6ccb52b864
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 63 additions and 18 deletions

View File

@ -14,12 +14,60 @@
#include "source/fuzz/fact_manager.h"
#include <sstream>
#include "source/fuzz/uniform_buffer_element_descriptor.h"
#include "source/opt/ir_context.h"
namespace spvtools {
namespace fuzz {
namespace {
std::string ToString(const protobufs::Fact& fact) {
assert(fact.fact_case() == protobufs::Fact::kConstantUniformFact &&
"Right now this is the only fact.");
std::stringstream stream;
stream << "("
<< fact.constant_uniform_fact()
.uniform_buffer_element_descriptor()
.descriptor_set()
<< ", "
<< fact.constant_uniform_fact()
.uniform_buffer_element_descriptor()
.binding()
<< ")[";
bool first = true;
for (auto index : fact.constant_uniform_fact()
.uniform_buffer_element_descriptor()
.index()) {
if (first) {
first = false;
} else {
stream << ", ";
}
stream << index;
}
stream << "] == [";
first = true;
for (auto constant_word : fact.constant_uniform_fact().constant_word()) {
if (first) {
first = false;
} else {
stream << ", ";
}
stream << constant_word;
}
stream << "]";
return stream.str();
}
} // namespace
// The purpose of this struct is to group the fields and data used to represent
// facts about uniform constants.
struct FactManager::ConstantUniformFacts {
@ -288,16 +336,16 @@ FactManager::FactManager() {
FactManager::~FactManager() = default;
bool FactManager::AddFacts(const protobufs::FactSequence& initial_facts,
void FactManager::AddFacts(const MessageConsumer& message_consumer,
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;
message_consumer(
SPV_MSG_WARNING, nullptr, {},
("Invalid fact " + ToString(fact) + " ignored.").c_str());
}
}
return true;
}
bool FactManager::AddFact(const spvtools::fuzz::protobufs::Fact& fact,

View File

@ -41,11 +41,14 @@ class 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);
// |context|. Warnings about invalid facts are communicated via
// |message_consumer|; such facts are otherwise ignored.
void AddFacts(const MessageConsumer& message_consumer,
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.
// Checks the fact for validity with respect to |context|. Returns false,
// with no side effects, if the fact is invalid. Otherwise adds |fact| to the
// fact manager.
bool AddFact(const protobufs::Fact& fact, opt::IRContext* context);
// The fact manager will ultimately be responsible for managing a few distinct

View File

@ -97,9 +97,7 @@ Fuzzer::FuzzerResultStatus Fuzzer::Run(
FuzzerContext fuzzer_context(&random_generator, minimum_fresh_id);
FactManager fact_manager;
if (!fact_manager.AddFacts(initial_facts, ir_context.get())) {
return Fuzzer::FuzzerResultStatus::kInitialFactsInvalid;
}
fact_manager.AddFacts(impl_->consumer, initial_facts, ir_context.get());
// Add some essential ingredients to the module if they are not already
// present, such as boolean constants.

View File

@ -33,7 +33,6 @@ class Fuzzer {
kComplete,
kFailedToCreateSpirvToolsInterface,
kInitialBinaryInvalid,
kInitialFactsInvalid,
};
// Constructs a fuzzer from the given target environment.

View File

@ -81,9 +81,7 @@ Replayer::ReplayerResultStatus Replayer::Run(
assert(ir_context);
FactManager fact_manager;
if (!fact_manager.AddFacts(initial_facts, ir_context.get())) {
return Replayer::ReplayerResultStatus::kInitialFactsInvalid;
}
fact_manager.AddFacts(impl_->consumer, initial_facts, ir_context.get());
// Consider the transformation proto messages in turn.
for (auto& message : transformation_sequence_in.transformation()) {

View File

@ -33,7 +33,6 @@ class Replayer {
kComplete,
kFailedToCreateSpirvToolsInterface,
kInitialBinaryInvalid,
kInitialFactsInvalid,
};
// Constructs a replayer from the given target environment.

View File

@ -257,7 +257,7 @@ int main(int argc, const char** argv) {
const std::string dot_spv(".spv");
std::string in_facts_file =
in_binary_file.substr(0, in_binary_file.length() - dot_spv.length()) +
".json";
".facts";
std::ifstream facts_input(in_facts_file);
if (facts_input) {
std::string facts_json_string((std::istreambuf_iterator<char>(facts_input)),