diff --git a/Core/HLE/sceKernelHeap.cpp b/Core/HLE/sceKernelHeap.cpp index 4c7c5d33dc..44e6e92961 100644 --- a/Core/HLE/sceKernelHeap.cpp +++ b/Core/HLE/sceKernelHeap.cpp @@ -184,6 +184,9 @@ static int sceKernelAllocHeapMemoryWithOption(int heapId, u32 memSize, u32 param } } // There's 8 bytes at the end of every block, reserved. + if (memSize > 0xFFFFFF00) { + return hleLogError(Log::sceKernel, 0, "invalid size %08x", memSize); + } memSize += 8; u32 addr = heap->alloc.AllocAligned(memSize, grain, grain, true); if (addr == (u32)-1) { diff --git a/Core/HLE/sceKernelInterrupt.cpp b/Core/HLE/sceKernelInterrupt.cpp index 0a7847adb8..ca9749a6c0 100644 --- a/Core/HLE/sceKernelInterrupt.cpp +++ b/Core/HLE/sceKernelInterrupt.cpp @@ -978,7 +978,8 @@ static u32 sysclib_strncpy(u32 dest, u32 src, u32 size) { // This is just regular strncpy, but being explicit to avoid warnings/safety fixes on missing null. u32 i = 0; - u32 srcSize = Memory::ClampValidSizeAt(src, size); + const u32 destSize = Memory::ClampValidSizeAt(dest, size); + const u32 srcSize = std::min(Memory::ClampValidSizeAt(src, size), destSize); const u8 *srcp = Memory::GetPointerUnchecked(src); u8 *destp = Memory::GetPointerWriteUnchecked(dest); for (i = 0; i < srcSize; ++i) { @@ -988,7 +989,6 @@ static u32 sysclib_strncpy(u32 dest, u32 src, u32 size) { *destp++ = c; } - u32 destSize = Memory::ClampValidSizeAt(dest, size); for (; i < destSize; ++i) { *destp++ = 0; } @@ -1013,7 +1013,10 @@ static u32 sysclib_strchr(u32 src, int c) { return hleLogError(Log::sceKernel, 0, "invalid address"); } const std::string str = Memory::GetCharPointer(src); - size_t cpos = str.find(str, c); + if ((char)c == 0) { + return hleLogVerbose(Log::sceKernel, src + (u32)str.size()); + } + size_t cpos = str.find((char)c); if (cpos == std::string::npos) { return hleLogVerbose(Log::sceKernel, 0); } @@ -1025,7 +1028,10 @@ static u32 sysclib_strrchr(u32 src, int c) { return hleLogError(Log::sceKernel, 0, "invalid address"); } const std::string str = Memory::GetCharPointer(src); - size_t cpos = str.rfind(str, c); + if ((char)c == 0) { + return hleLogVerbose(Log::sceKernel, src + (u32)str.size()); + } + size_t cpos = str.rfind((char)c); if (cpos == std::string::npos) { return hleLogVerbose(Log::sceKernel, 0); } diff --git a/Core/HLE/sceKernelMemory.cpp b/Core/HLE/sceKernelMemory.cpp index 53d19a3433..98997ac0c1 100644 --- a/Core/HLE/sceKernelMemory.cpp +++ b/Core/HLE/sceKernelMemory.cpp @@ -73,7 +73,8 @@ u32 FPL::GetMissingErrorCode() { int FPL::FindFreeBlock() { for (int i = 0; i < nf.numBlocks; i++) { - int b = nextBlock++ % nf.numBlocks; + int b = nextBlock % nf.numBlocks; + nextBlock = b + 1; if (!blocks[b]) { return b; } @@ -117,9 +118,10 @@ void FPL::DoState(PointerWrap &p) { FplWaitingThread dv = { 0 }; Do(p, waitingThreads, dv); Do(p, pausedWaits); - // It's taken modulo the block count, but a negative one stays negative. + // It's taken modulo the block count, but a negative one stays negative. Older versions let it + // overflow, so just restart the search. if (p.mode == p.MODE_READ && nextBlock < 0) { - p.SetError(p.ERROR_FAILURE); + nextBlock = 0; } } @@ -1829,25 +1831,20 @@ void __KernelTlsplThreadEnd(SceUID threadID) tls->waitingThreads.erase(std::remove(tls->waitingThreads.begin(), tls->waitingThreads.end(), threadID), tls->waitingThreads.end()); } - // Unlock all pools the thread had locked. + // Unlock all pools the thread had locked. Freeing mutates the map, so collect them first. + std::vector lockedIDs; auto locked = tlsplThreadEndChecks.equal_range(threadID); - for (TlsplMap::iterator iter = locked.first; iter != locked.second; ++iter) - { - SceUID tlsID = iter->second; - TLSPL *tls = kernelObjects.Get(tlsID, error); - - if (tls) - { - __KernelFreeTls(tls, threadID); - - // Restart the loop, freeing mutated it. - locked = tlsplThreadEndChecks.equal_range(threadID); - iter = locked.first; - if (locked.first == locked.second) - break; - } + for (TlsplMap::iterator iter = locked.first; iter != locked.second; ++iter) { + lockedIDs.push_back(iter->second); } tlsplThreadEndChecks.erase(locked.first, locked.second); + + for (SceUID tlsID : lockedIDs) { + TLSPL *tls = kernelObjects.Get(tlsID, error); + if (tls) { + __KernelFreeTls(tls, threadID); + } + } } SceUID sceKernelCreateTlspl(const char *name, u32 partition, u32 attr, u32 blockSize, u32 count, u32 optionsPtr) { diff --git a/Core/HLE/sceKernelModule.cpp b/Core/HLE/sceKernelModule.cpp index 596f1c9a55..54cb6bc162 100644 --- a/Core/HLE/sceKernelModule.cpp +++ b/Core/HLE/sceKernelModule.cpp @@ -3846,8 +3846,12 @@ static u32 sceKernelGetModuleIdList(u32 resultBuffer, u32 resultBufferSize, u32 u32 error; for (SceUID moduleId : loadedModules) { PSPModule *module = kernelObjects.Get(moduleId, error); + if (!module) { + continue; + } if (!module->isFake || liedAboutThisModule(module)) { - if (resultBufferOffset < resultBufferSize) { + // Only whole entries. + if (resultBufferOffset + 4 <= resultBufferSize) { Memory::WriteOrException_U32(module->GetUID(), resultBuffer + resultBufferOffset); resultBufferOffset += 4; }