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

Reply via email to