// Copyright 2021 The Tint Authors. // // 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 #include #include "fuzzers/tint_spirv_tools_fuzzer/util.h" namespace tint { namespace fuzzers { namespace spvtools_fuzzer { namespace util { namespace { bool WriteBinary(const std::string& path, const uint8_t* data, size_t size) { std::ofstream spv(path, std::ios::binary); return spv && spv.write(reinterpret_cast(data), static_cast(size)); } void LogError(uint32_t index, const std::string& type, const std::string& message, const std::string* path, const uint8_t* data, size_t size, const std::string* wgsl) { std::cout << index << " | " << type << ": " << message << std::endl; if (path) { auto prefix = *path + std::to_string(index); std::ofstream(prefix + ".log") << message << std::endl; WriteBinary(prefix + ".spv", data, size); if (wgsl) { std::ofstream(prefix + ".wgsl") << *wgsl << std::endl; } } } } // namespace spvtools::MessageConsumer GetBufferMessageConsumer(std::stringstream* buffer) { return [buffer](spv_message_level_t level, const char*, const spv_position_t& position, const char* message) { std::string status; switch (level) { case SPV_MSG_FATAL: case SPV_MSG_INTERNAL_ERROR: case SPV_MSG_ERROR: status = "ERROR"; break; case SPV_MSG_WARNING: case SPV_MSG_INFO: case SPV_MSG_DEBUG: status = "INFO"; break; } *buffer << status << " " << position.line << ":" << position.column << ":" << position.index << ": " << message << std::endl; }; } void LogMutatorError(const Mutator& mutator, const std::string& error_dir) { static uint32_t mutator_count = 0; auto error_path = error_dir.empty() ? error_dir : error_dir + "/mutator/"; mutator.LogErrors(error_dir.empty() ? nullptr : &error_path, mutator_count++); } void LogWgslError(const std::string& message, const uint8_t* data, size_t size, const std::string& wgsl, OutputFormat output_format, const std::string& error_dir) { static uint32_t wgsl_count = 0; std::string error_type; switch (output_format) { case OutputFormat::kSpv: error_type = "WGSL -> SPV"; break; case OutputFormat::kMSL: error_type = "WGSL -> MSL"; break; case OutputFormat::kHLSL: error_type = "WGSL -> HLSL"; break; case OutputFormat::kWGSL: error_type = "WGSL -> WGSL"; break; default: assert(false && "All output formats should've been handled"); break; } auto error_path = error_dir.empty() ? error_dir : error_dir + "/wgsl/"; LogError(wgsl_count++, error_type, message, error_dir.empty() ? nullptr : &error_path, data, size, &wgsl); } void LogSpvError(const std::string& message, const uint8_t* data, size_t size, const std::string& error_dir) { static uint32_t spv_count = 0; auto error_path = error_dir.empty() ? error_dir : error_dir + "/spv/"; LogError(spv_count++, "SPV -> WGSL", message, error_dir.empty() ? nullptr : &error_path, data, size, nullptr); } bool ReadBinary(const std::string& path, std::vector* out) { if (!out) { return false; } std::ifstream file(path, std::ios::binary | std::ios::ate); if (!file) { return false; } auto size = file.tellg(); if (!file) { return false; } file.seekg(0); if (!file) { return false; } std::vector binary(static_cast(size)); if (!file.read(binary.data(), size)) { return false; } out->resize(binary.size() / sizeof(uint32_t)); std::memcpy(out->data(), binary.data(), binary.size()); return true; } bool WriteBinary(const std::string& path, const std::vector& binary) { return WriteBinary(path, reinterpret_cast(binary.data()), binary.size() * sizeof(uint32_t)); } } // namespace util } // namespace spvtools_fuzzer } // namespace fuzzers } // namespace tint