From a87da59cebb15df408b037632f889f32e5d830ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Trung=20L=C3=AA?= <8@tle.id.au> Date: Wed, 25 Mar 2026 11:42:36 +1100 Subject: [PATCH] Fix ogg_sync_pageout hook The commit 2df07b59 has caused regression --- src/include/alternate.h | 2 ++ src/mallochook.c | 6 +++++- src/tools/alternate.c | 23 ++++++++++++++++++++++- 3 files changed, 29 insertions(+), 2 deletions(-) diff --git a/src/include/alternate.h b/src/include/alternate.h index 322635e37b..4eabf0e304 100644 --- a/src/include/alternate.h +++ b/src/include/alternate.h @@ -11,6 +11,8 @@ void* getAlternate(void* addr); void addAlternate(void* addr, void* alt); void addCheckAlternate(void* addr, void* alt); void cleanAlternate(void); +void suppressAlternate(void* addr); +void unsuppressAlternate(void* addr); #ifdef HAVE_ALTJUMP uintptr_t getAlternateJump(void* addr, int is32bits); #endif diff --git a/src/mallochook.c b/src/mallochook.c index 50ba713063..76b807e26b 100644 --- a/src/mallochook.c +++ b/src/mallochook.c @@ -881,8 +881,12 @@ static void* ogg_page_body_copy = NULL; static int my_ogg_sync_pageout_32(void* oy, void* og) { - // Call the original emulated ogg_sync_pageout + // Suppress the alternate for the duration of the call to avoid + // infinite recursion: RunFunctionFmt -> EmuRun -> getAlternate + // would redirect back to this hook without suppression. + suppressAlternate((void*)real_ogg_sync_pageout_32); int ret = (int)RunFunctionFmt(real_ogg_sync_pageout_32, "pp", oy, og); + unsuppressAlternate((void*)real_ogg_sync_pageout_32); if(ret > 0 && og) { // ogg_sync_pageout succeeded — og now has pointers into oy->data diff --git a/src/tools/alternate.c b/src/tools/alternate.c index 7597f63724..67110a27ae 100644 --- a/src/tools/alternate.c +++ b/src/tools/alternate.c @@ -20,9 +20,17 @@ typedef struct { KHASH_MAP_INIT_INT64(alternate, my_alternate_t) static kh_alternate_t *my_alternates = NULL; +// Per-address suppression: when set, getAlternate/hasAlternate/getAlternateJump +// will return "no alternate" for this specific address. Used by hooks that need +// to call through to the original emulated function via RunFunctionFmt without +// triggering infinite recursion (EmuRun applies getAlternate every iteration). +static uintptr_t alternate_suppress = 0; + int hasAlternate(void* addr) { if(!my_alternates) return 0; + if((uintptr_t)addr == alternate_suppress) + return 0; khint_t k = kh_get(alternate, my_alternates, (uintptr_t)addr); if(k==kh_end(my_alternates)) return 0; @@ -32,6 +40,8 @@ int hasAlternate(void* addr) { void* getAlternate(void* addr) { if(!my_alternates) return addr; + if((uintptr_t)addr == alternate_suppress) + return addr; khint_t k = kh_get(alternate, my_alternates, (uintptr_t)addr); if(k!=kh_end(my_alternates)) return kh_value(my_alternates, k).addr; @@ -53,6 +63,15 @@ void addAlternate(void* addr, void* alt) { #endif } +void suppressAlternate(void* addr) { + alternate_suppress = (uintptr_t)addr; +} + +void unsuppressAlternate(void* addr) { + (void)addr; + alternate_suppress = 0; +} + void addCheckAlternate(void* addr, void* alt) { if(!hasAlternate(addr)) addAlternate(addr, alt); @@ -70,6 +89,8 @@ void cleanAlternate() { uintptr_t getAlternateJump(void* addr, int is32bits) { if(!my_alternates) return 0; + if((uintptr_t)addr == alternate_suppress) + return 0; khint_t k = kh_get(alternate, my_alternates, (uintptr_t)addr); if(k!=kh_end(my_alternates)) { uintptr_t ret = kh_value(my_alternates, k).jump; @@ -78,4 +99,4 @@ uintptr_t getAlternateJump(void* addr, int is32bits) { } return 0; } -#endif \ No newline at end of file +#endif