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? 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) {