From b9fc587ac88e098613e33d12b77a8449ca93eabf Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Thu, 5 Nov 2026 20:25:03 -0800 Subject: [PATCH 1/3] CPUID: Fixes crash in CPUID When affinity changes are in play this can cause a crash because core index is larger than the number of cores known about. Happens on Frame. --- FEXCore/Source/Interface/Core/CPUID.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/FEXCore/Source/Interface/Core/CPUID.cpp b/FEXCore/Source/Interface/Core/CPUID.cpp index 489362c7d..5b4e6b083 100644 --- a/FEXCore/Source/Interface/Core/CPUID.cpp +++ b/FEXCore/Source/Interface/Core/CPUID.cpp @@ -1162,14 +1162,14 @@ FEXCore::CPUID::FunctionResults CPUIDEmu::Function_8000_0004h(uint32_t Leaf) con FEXCore::CPUID::FunctionResults CPUIDEmu::Function_8000_0002h(uint32_t Leaf, uint32_t CPU) const { FEXCore::CPUID::FunctionResults Res {}; - auto& Data = PerCPUData[CPU]; + auto& Data = PerCPUData[std::min(CPU, PerCPUData.size() - 1)]; memcpy(&Res, Data.ProductName, std::min(strlen(Data.ProductName), sizeof(FEXCore::CPUID::FunctionResults))); return Res; } FEXCore::CPUID::FunctionResults CPUIDEmu::Function_8000_0003h(uint32_t Leaf, uint32_t CPU) const { FEXCore::CPUID::FunctionResults Res {}; - auto& Data = PerCPUData[CPU]; + auto& Data = PerCPUData[std::min(CPU, PerCPUData.size() - 1)]; const auto RemainingStringSize = std::max(0, strlen(Data.ProductName) - 16); memcpy(&Res, Data.ProductName + 16, std::min(RemainingStringSize, sizeof(FEXCore::CPUID::FunctionResults))); return Res; @@ -1177,7 +1177,7 @@ FEXCore::CPUID::FunctionResults CPUIDEmu::Function_8000_0003h(uint32_t Leaf, uin FEXCore::CPUID::FunctionResults CPUIDEmu::Function_8000_0004h(uint32_t Leaf, uint32_t CPU) const { FEXCore::CPUID::FunctionResults Res {}; - auto& Data = PerCPUData[CPU]; + auto& Data = PerCPUData[std::min(CPU, PerCPUData.size() - 1)]; const auto RemainingStringSize = std::max(0, strlen(Data.ProductName) - 32); memcpy(&Res, Data.ProductName + 32, std::min(RemainingStringSize, sizeof(FEXCore::CPUID::FunctionResults))); return Res; From cf2f831ad9172b456fabe67526c5fc5c37658eb6 Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Thu, 5 Nov 2026 20:26:44 -0800 Subject: [PATCH 2/3] Windows: Fixes forced assert This wasn't ever wired up for Windows. --- Source/Windows/ARM64EC/Module.cpp | 5 +++++ Source/Windows/WOW64/Module.cpp | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/Source/Windows/ARM64EC/Module.cpp b/Source/Windows/ARM64EC/Module.cpp index 3be7e465a..167ae2777 100644 --- a/Source/Windows/ARM64EC/Module.cpp +++ b/Source/Windows/ARM64EC/Module.cpp @@ -903,6 +903,11 @@ bool ResetToConsistentStateImpl(const ThreadCPUArea CPUArea, EXCEPTION_RECORD* E return true; } + if (NativeContext->Pc == reinterpret_cast(&FEXCore::Assert::ForcedAssert)) { + LogMan::Msg::DFmt("FEX: Forced assert"); + NtTerminateProcess(NtCurrentProcess(), 0x42); + } + if (!IsJIT && !IsDispatcherAddress(NativeContext->Pc)) { LogMan::Msg::DFmt("Passing through exception"); return false; diff --git a/Source/Windows/WOW64/Module.cpp b/Source/Windows/WOW64/Module.cpp index 5660dcf39..b998af8d6 100644 --- a/Source/Windows/WOW64/Module.cpp +++ b/Source/Windows/WOW64/Module.cpp @@ -833,6 +833,11 @@ bool BTCpuResetToConsistentStateImpl(EXCEPTION_POINTERS* Ptrs) { } } + if (Context->Pc == reinterpret_cast(&FEXCore::Assert::ForcedAssert)) { + LogMan::Msg::DFmt("FEX: Forced assert"); + NtTerminateProcess(NtCurrentProcess(), 0x42); + } + if (!Thread || !IsAddressInJit(Context->Pc)) { return false; } From feee41a768f5b271ac854d40da17becc65b9cdd6 Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Thu, 5 Nov 2026 20:27:01 -0800 Subject: [PATCH 3/3] ImageTracker: Actually wire up config option for Volatile Metadata I forgot to wire this up, so you couldn't turn off an application's volatile metadata for testing. --- Source/Windows/Common/ImageTracker.cpp | 29 ++++++++++++++------------ 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/Source/Windows/Common/ImageTracker.cpp b/Source/Windows/Common/ImageTracker.cpp index c459c446f..dd22fe3ab 100644 --- a/Source/Windows/Common/ImageTracker.cpp +++ b/Source/Windows/Common/ImageTracker.cpp @@ -182,20 +182,23 @@ FEXCore::ExecutableFileSectionInfo ImageTracker::HandleImageMap(std::string_view } } - uint64_t EndAddress = Address + Nt->OptionalHeader.SizeOfImage; - fextl::set VolatileInstructions {}; - FEXCore::IntervalList VolatileValidRanges {}; - LoadImageVolatileMetadata(VolatileInstructions, VolatileValidRanges, Module, Nt, Address, EndAddress); - if (auto It = ExtendedMetaData.find(ID); It != ExtendedMetaData.end()) { - FEX::VolatileMetadata::ApplyFEXExtendedVolatileMetadata(It->second, VolatileInstructions, VolatileValidRanges, Address, EndAddress); - } - if (auto It = ExtendedMetaData.find(fextl::string {ModuleName}); It != ExtendedMetaData.end()) { - FEX::VolatileMetadata::ApplyFEXExtendedVolatileMetadata(It->second, VolatileInstructions, VolatileValidRanges, Address, EndAddress); - } - if (!VolatileInstructions.empty() || !VolatileValidRanges.Empty()) { - LogMan::Msg::DFmt("Loaded volatile metadata for {:X}: {} entries", Address, VolatileInstructions.size()); - CTX.AddForceTSOInformation(VolatileValidRanges, std::move(VolatileInstructions)); + if (FEXCore::Config::Get_VOLATILEMETADATA()) { + uint64_t EndAddress = Address + Nt->OptionalHeader.SizeOfImage; + fextl::set VolatileInstructions {}; + FEXCore::IntervalList VolatileValidRanges {}; + LoadImageVolatileMetadata(VolatileInstructions, VolatileValidRanges, Module, Nt, Address, EndAddress); + if (auto It = ExtendedMetaData.find(ID); It != ExtendedMetaData.end()) { + FEX::VolatileMetadata::ApplyFEXExtendedVolatileMetadata(It->second, VolatileInstructions, VolatileValidRanges, Address, EndAddress); + } + if (auto It = ExtendedMetaData.find(fextl::string {ModuleName}); It != ExtendedMetaData.end()) { + FEX::VolatileMetadata::ApplyFEXExtendedVolatileMetadata(It->second, VolatileInstructions, VolatileValidRanges, Address, EndAddress); + } + + if (!VolatileInstructions.empty() || !VolatileValidRanges.Empty()) { + LogMan::Msg::DFmt("Loaded volatile metadata for {:X}: {} entries", Address, VolatileInstructions.size()); + CTX.AddForceTSOInformation(VolatileValidRanges, std::move(VolatileInstructions)); + } } return ImageInfo->SectionInfo;