diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/SNES/LibsnesApi.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/SNES/LibsnesApi.cs index 741b8044d0..62ae3c73a7 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/SNES/LibsnesApi.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/SNES/LibsnesApi.cs @@ -349,9 +349,14 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES public void Seal() { - _core.SetBuffer(0, null, 0); - _core.SetBuffer(1, null, 0); - _core.SetBuffer(2, null, 0); + /* Cothreads can very easily acquire "pointer poison"; because their stack and even registers + * are part of state, any poisoned pointer that's used even temporarily might be persisted longer + * than needed. Most of the libsnes core cothreads handle internal matters only and aren't very + * vulnerable to pointer poison, but the main boss cothread is used heavily during init, when + * many syscalls happen and many kinds of poison can end up on the stack. so here, we call + * _core.DllInit() again, which recreates that cothread, zeroing out all of the memory first, + * as well as zeroing out the comm struct. */ + _core.DllInit(); _exe.Seal(); _sealed = true; } diff --git a/output64/dll/libco.so b/output64/dll/libco.so index 1a4cad5b71..6313c2ff1d 100644 Binary files a/output64/dll/libco.so and b/output64/dll/libco.so differ diff --git a/waterbox/libco/amd64.c b/waterbox/libco/amd64.c index 5f5a6cf8ff..a673917680 100644 --- a/waterbox/libco/amd64.c +++ b/waterbox/libco/amd64.c @@ -18,6 +18,25 @@ extern "C" { static long long co_active_buffer[64]; static cothread_t co_active_handle = 0; +static void* smalloc(size_t size) +{ + char* ret = malloc(size + 16); + if (ret) + { + *(size_t*)ret = size; + return ret + 16; + } + return NULL; +} + +static void sfree(void* ptr) +{ + char* original = (char*)ptr - 16; + size_t size = *(size_t*)original + 16; + memset(original, 0, size); + free(original); +} + extern void co_swap(cothread_t, cothread_t); static void crash() { @@ -39,7 +58,7 @@ cothread_t co_create(unsigned int size, void (*entrypoint)(void)) { size += 512; /* allocate additional space for storage */ size &= ~15; /* align stack to 16-byte boundary */ - if(handle = (cothread_t)malloc(size)) { + if(handle = (cothread_t)smalloc(size)) { long long *p = (long long*)((char*)handle + size); /* seek to top of stack */ *--p = (long long)crash; /* crash if entrypoint returns */ *--p = (long long)entrypoint; /* start of function */ @@ -50,7 +69,7 @@ cothread_t co_create(unsigned int size, void (*entrypoint)(void)) { } void co_delete(cothread_t handle) { - free(handle); + sfree(handle); } void co_switch(cothread_t handle) { diff --git a/waterbox/libco/libco.so b/waterbox/libco/libco.so index 1a4cad5b71..6313c2ff1d 100644 Binary files a/waterbox/libco/libco.so and b/waterbox/libco/libco.so differ diff --git a/waterbox/libsnes/bsnes/target-libsnes/libsnes_pwrap.cpp b/waterbox/libsnes/bsnes/target-libsnes/libsnes_pwrap.cpp index 237b789ecc..ce8f837bd2 100644 --- a/waterbox/libsnes/bsnes/target-libsnes/libsnes_pwrap.cpp +++ b/waterbox/libsnes/bsnes/target-libsnes/libsnes_pwrap.cpp @@ -613,10 +613,16 @@ EXPORT void* DllInit() T(privbuf, 232); #undef T - memset(&comm,0,sizeof(comm)); + memset(&comm, 0, sizeof(comm)); //make a coroutine thread to run the emulation in. we'll switch back to this cothread when communicating with the frontend co_control = co_active(); + if (co_emu) + { + // if this was called again, that's OK; delete the old emuthread + co_delete(co_emu); + co_emu = nullptr; + } co_emu = co_create(65536 * sizeof(void*), new_emuthread); return &comm;