From 770438cee031f7a972a096ebd8f0c65a7575f8ed Mon Sep 17 00:00:00 2001 From: "Mr. Big Britches" <111622360+MrBigBritches@users.noreply.github.com> Date: Mon, 26 Oct 2026 22:26:08 -0700 Subject: [PATCH] ci: fix the Linux build and the macOS SRT walker test crashes (#1922) * graphics: give InlinePageOwnerList's const_iterator iterator traits The Linux build failed in textureCache.cpp: std::any_of over the image owners of a page needs std::iterator_traits, which libstdc++ only fills from the iterator's own member types. MSVC's STL and libc++ don't consult them there, so Windows and macOS built. Declare the five member types. The category is input, not forward, because operator* returns a copy. Co-Authored-By: Claude Opus 5.5 * tests: assert InlinePageOwnerList's const_iterator has an input category Only libstdc++ needs the iterator traits for std::any_of, so removing them would compile on Windows and macOS and break only the Linux build. The assert fails the build on every platform instead. Co-Authored-By: Claude Opus 5.5 * tests: serve SRT walker test loads on macOS too FakeGuestMemory only installed its fault handler on Linux and Windows, so on macOS the walker's deliberately faulting loads crashed scalar_provenance, resource_materialization and resource_tracking. Share the Linux sigaction path with macOS, read the registers from the macOS thread state, and catch SIGBUS as well as SIGSEGV there, like the emulator's own handler. Co-Authored-By: Claude Opus 5.5 --------- Co-authored-by: Claude Opus 5.5 --- .../renderer/cache/multiLevelPageTable.h | 8 ++++ tests/ImagePageTableTests.cpp | 7 ++++ tests/SrtWalkerTestMemory.h | 42 ++++++++++++++----- 3 files changed, 46 insertions(+), 11 deletions(-) diff --git a/src/graphics/host_gpu/renderer/cache/multiLevelPageTable.h b/src/graphics/host_gpu/renderer/cache/multiLevelPageTable.h index 7fac1d8e0..ad18d6765 100644 --- a/src/graphics/host_gpu/renderer/cache/multiLevelPageTable.h +++ b/src/graphics/host_gpu/renderer/cache/multiLevelPageTable.h @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -118,6 +119,13 @@ public: class const_iterator final { public: + // libstdc++'s algorithms need these. Input, not forward, because operator* returns a copy. + using iterator_category = std::input_iterator_tag; + using value_type = OwnerT; + using difference_type = std::ptrdiff_t; + using pointer = void; + using reference = OwnerT; + [[nodiscard]] OwnerT operator*() const noexcept { return m_owners->At(m_index); } const_iterator& operator++() noexcept { ++m_index; diff --git a/tests/ImagePageTableTests.cpp b/tests/ImagePageTableTests.cpp index 44f82745a..435ae7bbc 100644 --- a/tests/ImagePageTableTests.cpp +++ b/tests/ImagePageTableTests.cpp @@ -3,6 +3,8 @@ #include #include #include +#include +#include #include #include @@ -13,6 +15,11 @@ using Table = Libs::Graphics::MultiLevelPageTable; using PageOwners = Libs::Graphics::InlinePageOwnerList; using OwnerTable = Libs::Graphics::MultiLevelPageTable; +// MSVC's STL and libc++ don't need these traits for std::any_of, but libstdc++ does, so only a +// Linux build would notice them missing. +static_assert(std::is_same_v::iterator_category, + std::input_iterator_tag>); + void Check(bool value, const char* text) { if (!value) { std::fprintf(stderr, "ImagePageTableTests: failed: %s\n", text); diff --git a/tests/SrtWalkerTestMemory.h b/tests/SrtWalkerTestMemory.h index b792237d4..443256bc6 100644 --- a/tests/SrtWalkerTestMemory.h +++ b/tests/SrtWalkerTestMemory.h @@ -6,12 +6,16 @@ #include #include +#include #include +#include #include #include #if defined(__linux__) #include +#elif defined(__APPLE__) +#include #elif defined(_WIN32) #include #endif @@ -23,18 +27,20 @@ public: explicit FakeGuestMemory(Libs::Graphics::ShaderRecompiler::IR::SrtMemoryReader reader = nullptr, void *userdata = nullptr) { Current() = {reader, userdata}; -#if defined(__linux__) +#if defined(__linux__) || defined(__APPLE__) struct sigaction action {}; action.sa_sigaction = Handle; action.sa_flags = SA_SIGINFO; - sigaction(SIGSEGV, &action, &m_previous); + for (size_t index = 0; index < std::size(kSignals); ++index) + sigaction(kSignals[index], &action, &m_previous[index]); #elif defined(_WIN32) m_handler = AddVectoredExceptionHandler(1, Handle); #endif } ~FakeGuestMemory() { -#if defined(__linux__) - sigaction(SIGSEGV, &m_previous, nullptr); +#if defined(__linux__) || defined(__APPLE__) + for (size_t index = 0; index < std::size(kSignals); ++index) + sigaction(kSignals[index], &m_previous[index], nullptr); #elif defined(_WIN32) RemoveVectoredExceptionHandler(m_handler); #endif @@ -54,16 +60,30 @@ private: const auto [reader, userdata] = Current(); return reader != nullptr && reader(userdata, address, {&word, 1}) ? word : 0u; } -#if defined(__linux__) +#if defined(__linux__) || defined(__APPLE__) +#if defined(__APPLE__) + // macOS raises SIGBUS for some protection faults and SIGSEGV for others. + static constexpr int kSignals[] = {SIGSEGV, SIGBUS}; +#else + static constexpr int kSignals[] = {SIGSEGV}; +#endif static void Handle(int, siginfo_t *, void *context) { - auto ®isters = static_cast(context)->uc_mcontext.gregs; - const auto length = - Libs::Graphics::ShaderRecompiler::IR::SrtWalkerLoadLength(registers[REG_RIP]); + auto *native = static_cast(context); +#if defined(__APPLE__) + auto &rip = native->uc_mcontext->__ss.__rip; + auto &rax = native->uc_mcontext->__ss.__rax; + const auto r10 = native->uc_mcontext->__ss.__r10; +#else + auto &rip = native->uc_mcontext.gregs[REG_RIP]; + auto &rax = native->uc_mcontext.gregs[REG_RAX]; + const auto r10 = native->uc_mcontext.gregs[REG_R10]; +#endif + const auto length = Libs::Graphics::ShaderRecompiler::IR::SrtWalkerLoadLength(rip); if (length == 0) std::abort(); - registers[REG_RAX] = Read(registers[REG_R10]); - registers[REG_RIP] += length; + rax = Read(r10); + rip += length; } - struct sigaction m_previous {}; + struct sigaction m_previous[std::size(kSignals)] {}; #elif defined(_WIN32) static LONG CALLBACK Handle(EXCEPTION_POINTERS *info) { auto &context = *info->ContextRecord;