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