mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-11-12 09:09:29 +01:00
Don't drop an ISO's trailing partial sector
Not every disc image is a whole number of 2048-byte sectors - tools that build pre-patched ISOs write images that stop partway through their last one, with a file legitimately ending there. Two things then conspired to lose that tail. FileBlockDevice::GetNumBlocks() rounds down, so the partial sector isn't counted, and the file size clamp in ISOFileSystem measured what the image holds in whole blocks. A file running to the last byte of such an image got clamped short - by up to a sector - before anything read it. FileBlockDevice::ReadBlock() then returned false for a short read of that sector, and ISOFileSystem::ReadFile substitutes an all-zero sector when a read fails, so even the bytes that were there came back as zeroes. Measure the clamp in bytes via GetUncompressedSize() instead of blocks, and treat a short read at the end of the image as a success with the rest of the sector zeroed. GetUncompressedSize() defaults to the block-based value and is only overridden by FileBlockDevice, so nothing else changes behaviour. Also report why a module was rejected. "Failed to load module" named the file and nothing else, and the truncation check logged only the byte count, which points at the executable when the real cause is that the loader was handed fewer bytes than the file has. ElfReader now keeps the reason for a failed LoadInto, __KernelLoadELFFromPtr puts it in the error string that reaches the user, and both messages say which header table overran and by how much. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
1fc823681f
commit
51ec045947
5 files changed
+48
-8
No files matched your search
+12
-2
@@ -544,8 +544,18 @@ int ElfReader::LoadInto(u32 loadAddress, bool fromTop) {
|
||||
if (header->e_ident[EI_DATA] != ELFDATA2LSB)
|
||||
return SCE_KERNEL_ERROR_MEMBLOCK_ALLOC_FAILED;
|
||||
|
||||
if (size_ < header->e_phoff + sizeof(Elf32_Phdr) * GetNumSegments() || size_ < header->e_shoff + sizeof(Elf32_Shdr) * GetNumSections()) {
|
||||
ERROR_LOG(Log::Loader, "Truncated ELF, %d bytes with %d sections and %d segments", (int)size_, GetNumSections(), GetNumSegments());
|
||||
const size_t phdrEnd = header->e_phoff + sizeof(Elf32_Phdr) * GetNumSegments();
|
||||
const size_t shdrEnd = header->e_shoff + sizeof(Elf32_Shdr) * GetNumSections();
|
||||
if (size_ < phdrEnd || size_ < shdrEnd) {
|
||||
// Say which table runs off the end and by how much. "Truncated ELF" on its own sends you
|
||||
// looking at the executable, when the usual cause is that we were handed fewer bytes than
|
||||
// the file really has - a short read, or a size clamped somewhere upstream.
|
||||
const char *which = size_ < phdrEnd ? "program header table" : "section header table";
|
||||
const size_t needed = size_ < phdrEnd ? phdrEnd : shdrEnd;
|
||||
loadError_ = StringFromFormat(
|
||||
"Truncated ELF: %s ends at %d but only %d bytes are available (%d short), %d sections, %d segments",
|
||||
which, (int)needed, (int)size_, (int)(needed - size_), GetNumSections(), GetNumSegments());
|
||||
ERROR_LOG(Log::Loader, "%s", loadError_.c_str());
|
||||
// Probably not the right error code.
|
||||
return SCE_KERNEL_ERROR_MEMBLOCK_ALLOC_FAILED;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user