From 67f2bf57cb6cf0ead7c87123773c52fc0db196eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 11 Aug 2026 01:34:10 +0200 Subject: [PATCH] RamCachingFileLoader: don't round a mid-file short read up to a full block blocksActuallyRead rounded bytesRead up to the next whole block unconditionally, intending to handle the legitimate case where the very last block of the file is naturally shorter than BLOCK_SIZE (cache_ is deliberately over-allocated for that). But it applied the same rounding to any short read, including a genuine failure or a dropped connection mid-file (this loader can sit on top of the whole Remote ISO chain via CachingFileLoader/HTTPFileLoader when "Cache full ISO in RAM" is enabled) - marking a block as fully cached when only a few of its bytes were actually written. Since cache_ is malloc'd (not zeroed), every later read of that block would serve uninitialized heap memory as if it were real file data. Only round up when the short read's end position exactly matches the true end of the file. --- Core/FileLoaders/RamCachingFileLoader.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/Core/FileLoaders/RamCachingFileLoader.cpp b/Core/FileLoaders/RamCachingFileLoader.cpp index 8e4808c771..2e402ff1d4 100644 --- a/Core/FileLoaders/RamCachingFileLoader.cpp +++ b/Core/FileLoaders/RamCachingFileLoader.cpp @@ -189,7 +189,16 @@ void RamCachingFileLoader::SaveIntoCache(s64 pos, size_t bytes, Flags flags) { size_t bytesRead = backend_->ReadAt(cacheFilePos, blocksToRead << BLOCK_SHIFT, &cache_[cacheFilePos], flags); // In case there was an error, let's not mark blocks that failed to read as read. - u32 blocksActuallyRead = (u32)((bytesRead + BLOCK_SIZE - 1) >> BLOCK_SHIFT); + // Round up only for a genuine short read exactly at the true end of the file - + // cache_ is deliberately over-allocated to a full BLOCK_SIZE for the last block, + // so its unwritten tail past filesize_ is never read back. Any other short read + // (e.g. a dropped Remote ISO connection mid-file) must not be rounded up, or the + // unwritten (uninitialized, since cache_ is malloc'd) rest of that block would be + // served as if it were real file data. + u32 blocksActuallyRead = (u32)(bytesRead >> BLOCK_SHIFT); + if ((bytesRead & (BLOCK_SIZE - 1)) != 0 && cacheFilePos + (s64)bytesRead == filesize_) { + ++blocksActuallyRead; + } { std::lock_guard guard(blocksMutex_);