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 коммит произвёл GitHub
Родитель 88183041d5
Коммит 6ccb52b864
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
7 изменённых файлов: 63 добавлений и 18 удалений

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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