On Mon, Oct 21, 2019 at 03:23:01AM -0600, Anthony J. Bentley wrote: > Hi, > > higan includes a cooperative multithreading library, libco, that swaps > contexts causing the emulator to crash with MAP_STACK violations. > > Replacing malloc() with mmap(...MAP_STACK...) is enough to eliminate > crashes. But this also means replacing free() with munmap(). Unlike > free(), munmap() requires the allocated size. However, higan doesn't > keep track of the size, and thus it can't be passed to munmap(). I > don't think developing and maintaining local patches to keep track of > size is practical. > > The end result is that the below diff prevents the MAP_STACK crash, but > also leaks mmap()ed memory. > > Without this, higan is unusable. Should I just commit it anyway? > Any other ideas?
It looks like all relevant free() calls are wrapped by a function like this: void co_delete(cothread_t t) { free(t); } Storing the allocated size in a new field of cothread_t is not an option? E.g. the free parts would then look like this, assuming a new 'size' field added to that struct and initialized after allocation: void co_delete(cothread_t t) { size_t size = t->size, munmap(t, size); } > Index: Makefile > =================================================================== > RCS file: /cvs/ports/emulators/higan/Makefile,v > retrieving revision 1.6 > diff -u -p -r1.6 Makefile > --- Makefile 12 Jul 2019 20:46:09 -0000 1.6 > +++ Makefile 21 Oct 2019 09:19:23 -0000 > @@ -5,7 +5,7 @@ COMMENT = multi-system Nintendo emulator > V = 106 > DISTNAME = higan_v$V-source > PKGNAME = higan-$V > -REVISION = 3 > +REVISION = 4 > > USE_WXNEEDED = Yes > > Index: patches/patch-libco_amd64_c > =================================================================== > RCS file: patches/patch-libco_amd64_c > diff -N patches/patch-libco_amd64_c > --- /dev/null 1 Jan 1970 00:00:00 -0000 > +++ patches/patch-libco_amd64_c 21 Oct 2019 09:19:23 -0000 > @@ -0,0 +1,26 @@ > +$OpenBSD$ > + > +Index: libco/amd64.c > +--- libco/amd64.c.orig > ++++ libco/amd64.c > +@@ -130,7 +130,10 @@ cothread_t co_create(unsigned int size, void (*entrypo > + size += 512; /* allocate additional space for storage */ > + size &= ~15; /* align stack to 16-byte boundary */ > + > +- if(handle = (cothread_t)malloc(size)) { > ++ handle = (cothread_t)mmap(0, size, PROT_READ|PROT_WRITE, > MAP_PRIVATE|MAP_ANONYMOUS|MAP_STACK, -1, 0); > ++ if(handle == MAP_FAILED) { > ++ err(1, "libco mmap failed"); > ++ } else { > + 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 */ > +@@ -141,7 +144,7 @@ cothread_t co_create(unsigned int size, void (*entrypo > + } > + > + void co_delete(cothread_t handle) { > +- free(handle); > ++ //free(handle); > + } > + > + void co_switch(cothread_t handle) { > Index: patches/patch-libco_arm_c > =================================================================== > RCS file: patches/patch-libco_arm_c > diff -N patches/patch-libco_arm_c > --- /dev/null 1 Jan 1970 00:00:00 -0000 > +++ patches/patch-libco_arm_c 21 Oct 2019 09:19:23 -0000 > @@ -0,0 +1,26 @@ > +$OpenBSD$ > + > +Index: libco/arm.c > +--- libco/arm.c.orig > ++++ libco/arm.c > +@@ -50,7 +50,10 @@ cothread_t co_create(unsigned int size, void (*entrypo > + size += 256; > + size &= ~15; > + > +- if(handle = (unsigned long*)malloc(size)) { > ++ handle = (unsigned long*)mmap(0, size, PROT_READ|PROT_WRITE, > MAP_PRIVATE|MAP_ANONYMOUS|MAP_STACK, -1, 0); > ++ if(handle == MAP_FAILED) { > ++ err(1, "libco mmap failed"); > ++ } else { > + unsigned long* p = (unsigned long*)((unsigned char*)handle + size); > + handle[8] = (unsigned long)p; > + handle[9] = (unsigned long)entrypoint; > +@@ -60,7 +63,7 @@ cothread_t co_create(unsigned int size, void (*entrypo > + } > + > + void co_delete(cothread_t handle) { > +- free(handle); > ++ //free(handle); > + } > + > + void co_switch(cothread_t handle) { > Index: patches/patch-libco_libco_h > =================================================================== > RCS file: patches/patch-libco_libco_h > diff -N patches/patch-libco_libco_h > --- /dev/null 1 Jan 1970 00:00:00 -0000 > +++ patches/patch-libco_libco_h 21 Oct 2019 09:19:23 -0000 > @@ -0,0 +1,14 @@ > +$OpenBSD$ > + > +Index: libco/libco.h > +--- libco/libco.h.orig > ++++ libco/libco.h > +@@ -7,6 +7,8 @@ > + #ifndef LIBCO_H > + #define LIBCO_H > + > ++#include <err.h> > ++ > + #ifdef __cplusplus > + extern "C" { > + #endif > Index: patches/patch-libco_ppc_c > =================================================================== > RCS file: patches/patch-libco_ppc_c > diff -N patches/patch-libco_ppc_c > --- /dev/null 1 Jan 1970 00:00:00 -0000 > +++ patches/patch-libco_ppc_c 21 Oct 2019 09:19:23 -0000 > @@ -0,0 +1,26 @@ > +$OpenBSD$ > + > +Index: libco/ppc.c > +--- libco/ppc.c.orig > ++++ libco/ppc.c > +@@ -261,7 +261,10 @@ static const uint32_t libco_ppc_code[1024] = { > + static uint32_t* co_create_(unsigned size, uintptr_t entry) { > + (void)entry; > + > +- uint32_t* t = (uint32_t*)malloc(size); > ++ uint32_t* t = (uint32_t*)mmap(0, size, PROT_READ|PROT_WRITE, > MAP_PRIVATE|MAP_ANONYMOUS|MAP_STACK, -1, 0); > ++ if(t == MAP_FAILED) { > ++ err(1, "libco mmap failed"); > ++ } > + > + #if LIBCO_PPCDESC > + if(t) { > +@@ -324,7 +327,7 @@ cothread_t co_create(unsigned int size, void (*entry_) > + } > + > + void co_delete(cothread_t t) { > +- free(t); > ++ //free(t); > + } > + > + static void co_init_(void) { > Index: patches/patch-libco_x86_c > =================================================================== > RCS file: patches/patch-libco_x86_c > diff -N patches/patch-libco_x86_c > --- /dev/null 1 Jan 1970 00:00:00 -0000 > +++ patches/patch-libco_x86_c 21 Oct 2019 09:19:23 -0000 > @@ -0,0 +1,26 @@ > +$OpenBSD$ > + > +Index: libco/x86.c > +--- libco/x86.c.orig > ++++ libco/x86.c > +@@ -84,7 +84,10 @@ cothread_t co_create(unsigned int size, void (*entrypo > + size += 256; /* allocate additional space for storage */ > + size &= ~15; /* align stack to 16-byte boundary */ > + > +- if(handle = (cothread_t)malloc(size)) { > ++ handle = (cothread_t)mmap(0, size, PROT_READ|PROT_WRITE, > MAP_PRIVATE|MAP_ANONYMOUS|MAP_STACK, -1, 0); > ++ if(handle == MAP_FAILED) { > ++ err(1, "libco mmap failed"); > ++ } else { > + long *p = (long*)((char*)handle + size); /* seek to top of stack */ > + *--p = (long)crash; /* crash if entrypoint > returns */ > + *--p = (long)entrypoint; /* start of function */ > +@@ -95,7 +98,7 @@ cothread_t co_create(unsigned int size, void (*entrypo > + } > + > + void co_delete(cothread_t handle) { > +- free(handle); > ++ //free(handle); > + } > + > + void co_switch(cothread_t handle) { > >