From d509370217833e2f0572e4e3f71bcb0b397a90e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Fri, 23 Oct 2026 22:06:21 +0200 Subject: [PATCH] POPS: Give the disc switching table's empty strings a real, empty string Older emulators (3.95 to 4.05) read an empty string's first character, and a null pointer there crashed them as soon as they drew the menu, with one disc too. Co-Authored-By: Claude Opus 5.5 (1M context) --- Core/HLE/PopsBoot.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/Core/HLE/PopsBoot.cpp b/Core/HLE/PopsBoot.cpp index 867ed12ffd..45cb6a0efc 100644 --- a/Core/HLE/PopsBoot.cpp +++ b/Core/HLE/PopsBoot.cpp @@ -617,12 +617,12 @@ static bool InstallDiscSwitchText(u32 stringTable, u32 positionTable, u32 resetT } } + // Each ends in a zero, so an empty one is a string too: older emulators read its first character. u32 size = 0; for (const std::u16string &s : text.strings) { - size += ((u32)s.size() * 2 + 3) & ~3; + size += ((u32)s.size() * 2 + 2 + 3) & ~3; } - u32 alloc = std::max(size, 4U); - const u32 strings = kernelMemory.Alloc(alloc, false, "PopsDiscText"); + const u32 strings = kernelMemory.Alloc(size, false, "PopsDiscText"); if (strings == (u32)-1) { return false; } @@ -634,9 +634,10 @@ static bool InstallDiscSwitchText(u32 stringTable, u32 positionTable, u32 resetT for (size_t c = 0; c < s.size(); c++) { Memory::WriteUnchecked_U16(s[s.size() - 1 - c], ptr + (u32)c * 2); } + Memory::WriteUnchecked_U16(0, ptr + (u32)s.size() * 2); entries[i][0] = (u32)s.size(); - entries[i][1] = s.empty() ? 0 : ptr; - ptr += ((u32)s.size() * 2 + 3) & ~3; + entries[i][1] = ptr; + ptr += ((u32)s.size() * 2 + 2 + 3) & ~3; } for (int lang = 0; lang < POPS_LANGUAGES; lang++) { for (int i = 0; i < DISC_STRING_COUNT; i++) {