diff --git a/GPU/Vulkan/PipelineManagerVulkan.cpp b/GPU/Vulkan/PipelineManagerVulkan.cpp index 376460f910..4498dedb78 100644 --- a/GPU/Vulkan/PipelineManagerVulkan.cpp +++ b/GPU/Vulkan/PipelineManagerVulkan.cpp @@ -592,6 +592,7 @@ void PipelineManagerVulkan::SaveCache(FILE *file, bool saveRawPipelineCache, Sha size_t seekPosOnFailure = ftell(file); bool failed = false; + bool writeFailed = false; int count = 0; // Since we don't include the full pipeline key, there can be duplicates, // caused by things like switching from buffered to non-buffered rendering. @@ -630,11 +631,11 @@ void PipelineManagerVulkan::SaveCache(FILE *file, bool saveRawPipelineCache, Sha // Write the number of pipelines. size = (uint32_t)keys.size(); - fwrite(&size, sizeof(size), 1, file); + writeFailed = writeFailed || fwrite(&size, sizeof(size), 1, file) != 1; // Write the pipelines. for (auto &key : keys) { - fwrite(&key, sizeof(key), 1, file); + writeFailed = writeFailed || fwrite(&key, sizeof(key), 1, file) != 1; } if (failed) { @@ -642,10 +643,17 @@ void PipelineManagerVulkan::SaveCache(FILE *file, bool saveRawPipelineCache, Sha // Write a zero in the right place so it doesn't try to load the pipelines next time. size = 0; fseek(file, (long)seekPosOnFailure, SEEK_SET); - fwrite(&size, sizeof(size), 1, file); + writeFailed = fwrite(&size, sizeof(size), 1, file) != 1; + if (writeFailed) { + ERROR_LOG(G3D, "Failed to write pipeline cache, disk full?"); + } return; } - NOTICE_LOG(G3D, "Saved Vulkan pipeline ID cache (%d unique pipelines/%d).", (int)keys.size(), (int)pipelines_.size()); + if (writeFailed) { + ERROR_LOG(G3D, "Failed to write pipeline cache, disk full?"); + } else { + NOTICE_LOG(G3D, "Saved Vulkan pipeline ID cache (%d unique pipelines/%d).", (int)keys.size(), (int)pipelines_.size()); + } } bool PipelineManagerVulkan::LoadCache(FILE *file, bool loadRawPipelineCache, ShaderManagerVulkan *shaderManager, Draw::DrawContext *drawContext, VkPipelineLayout layout) { @@ -654,16 +662,16 @@ bool PipelineManagerVulkan::LoadCache(FILE *file, bool loadRawPipelineCache, Sha uint32_t size = 0; if (loadRawPipelineCache) { - fread(&size, sizeof(size), 1, file); - if (!size) { + bool success = fread(&size, sizeof(size), 1, file) == 1; + if (!size || !success) { WARN_LOG(G3D, "Zero-sized Vulkan pipeline cache."); return true; } std::unique_ptr buffer(new uint8_t[size]); - fread(buffer.get(), 1, size, file); + success = fread(buffer.get(), 1, size, file) == size; // Verify header. VkPipelineCacheHeader *header = (VkPipelineCacheHeader *)buffer.get(); - if (header->version != VK_PIPELINE_CACHE_HEADER_VERSION_ONE) { + if (!success || header->version != VK_PIPELINE_CACHE_HEADER_VERSION_ONE) { // Bad header, don't do anything. WARN_LOG(G3D, "Bad Vulkan pipeline cache header - ignoring"); return false; @@ -697,16 +705,19 @@ bool PipelineManagerVulkan::LoadCache(FILE *file, bool loadRawPipelineCache, Sha } // Read the number of pipelines. - fread(&size, sizeof(size), 1, file); + bool failed = fread(&size, sizeof(size), 1, file) != 1; NOTICE_LOG(G3D, "Creating %d pipelines...", size); - bool failed = false; for (uint32_t i = 0; i < size; i++) { if (failed) { - continue; + break; } StoredVulkanPipelineKey key; - fread(&key, sizeof(key), 1, file); + failed = failed || fread(&key, sizeof(key), 1, file) != 1; + if (failed) { + ERROR_LOG(G3D, "Truncated Vulkan pipeline cache file"); + continue; + } VulkanVertexShader *vs = shaderManager->GetVertexShaderFromID(key.vShaderID); VulkanFragmentShader *fs = shaderManager->GetFragmentShaderFromID(key.fShaderID); if (!vs || !fs) { diff --git a/GPU/Vulkan/ShaderManagerVulkan.cpp b/GPU/Vulkan/ShaderManagerVulkan.cpp index 17106e0951..832e45aa75 100644 --- a/GPU/Vulkan/ShaderManagerVulkan.cpp +++ b/GPU/Vulkan/ShaderManagerVulkan.cpp @@ -366,8 +366,8 @@ struct VulkanCacheHeader { bool ShaderManagerVulkan::LoadCache(FILE *f) { VulkanCacheHeader header{}; - fread(&header, sizeof(header), 1, f); - if (header.magic != CACHE_HEADER_MAGIC) + bool success = fread(&header, sizeof(header), 1, f) == 1; + if (!success || header.magic != CACHE_HEADER_MAGIC) return false; if (header.version != CACHE_VERSION) return false; @@ -376,7 +376,10 @@ bool ShaderManagerVulkan::LoadCache(FILE *f) { for (int i = 0; i < header.numVertexShaders; i++) { VShaderID id; - fread(&id, sizeof(id), 1, f); + if (fread(&id, sizeof(id), 1, f) != 1) { + ERROR_LOG(G3D, "Vulkan shader cache truncated"); + break; + } bool useHWTransform = id.Bit(VS_BIT_USE_HW_TRANSFORM); GenerateVulkanGLSLVertexShader(id, codeBuffer_); VulkanVertexShader *vs = new VulkanVertexShader(vulkan_, id, codeBuffer_, useHWTransform); @@ -384,7 +387,10 @@ bool ShaderManagerVulkan::LoadCache(FILE *f) { } for (int i = 0; i < header.numFragmentShaders; i++) { FShaderID id; - fread(&id, sizeof(id), 1, f); + if (fread(&id, sizeof(id), 1, f) != 1) { + ERROR_LOG(G3D, "Vulkan shader cache truncated"); + break; + } GenerateVulkanGLSLFragmentShader(id, codeBuffer_); VulkanFragmentShader *fs = new VulkanFragmentShader(vulkan_, id, codeBuffer_); fsCache_.Insert(id, fs); @@ -402,12 +408,16 @@ void ShaderManagerVulkan::SaveCache(FILE *f) { header.reserved = 0; header.numVertexShaders = (int)vsCache_.size(); header.numFragmentShaders = (int)fsCache_.size(); - fwrite(&header, sizeof(header), 1, f); + bool writeFailed = fwrite(&header, sizeof(header), 1, f) != 1; vsCache_.Iterate([&](const VShaderID &id, VulkanVertexShader *vs) { - fwrite(&id, sizeof(id), 1, f); + writeFailed = writeFailed || fwrite(&id, sizeof(id), 1, f) != 1; }); fsCache_.Iterate([&](const FShaderID &id, VulkanFragmentShader *fs) { - fwrite(&id, sizeof(id), 1, f); + writeFailed = writeFailed || fwrite(&id, sizeof(id), 1, f) != 1; }); - NOTICE_LOG(G3D, "Saved %d vertex and %d fragment shaders", header.numVertexShaders, header.numFragmentShaders); + if (writeFailed) { + ERROR_LOG(G3D, "Failed to write Vulkan shader cache, disk full?"); + } else { + NOTICE_LOG(G3D, "Saved %d vertex and %d fragment shaders", header.numVertexShaders, header.numFragmentShaders); + } }