summaryrefslogtreecommitdiff
path: root/ext/ffi_c
diff options
context:
space:
mode:
authorWatson <watson1978@gmail.com>2020-07-13 21:51:57 +0900
committerWatson <watson1978@gmail.com>2020-07-18 13:11:33 +0900
commit2c9c517876fd115191cd05f62ff8e77ebd493641 (patch)
treea612f3d1a970f707424c334e20b15492506957d4 /ext/ffi_c
parentd15fa0615df0f20fbcf4b3c23a353a4ec002f555 (diff)
downloadffi-2c9c517876fd115191cd05f62ff8e77ebd493641.tar.gz
Use ffi_closure_alloc() on Apple silicon to fix crash
Diffstat (limited to 'ext/ffi_c')
-rw-r--r--ext/ffi_c/ClosurePool.c67
-rw-r--r--ext/ffi_c/ClosurePool.h2
-rw-r--r--ext/ffi_c/Function.c2
-rw-r--r--ext/ffi_c/MethodHandle.c2
4 files changed, 71 insertions, 2 deletions
diff --git a/ext/ffi_c/ClosurePool.c b/ext/ffi_c/ClosurePool.c
index 45411b4..ea660b0 100644
--- a/ext/ffi_c/ClosurePool.c
+++ b/ext/ffi_c/ClosurePool.c
@@ -66,6 +66,11 @@
#include "ClosurePool.h"
+#if (defined(__arm64__) && defined(__APPLE__))
+#define USE_FFI_ALLOC 1
+#else
+#define USE_FFI_ALLOC 0
+#endif
#ifndef roundup
# define roundup(x, y) ((((x)+((y)-1))/(y))*(y))
@@ -115,7 +120,11 @@ cleanup_closure_pool(ClosurePool* pool)
for (memory = pool->blocks; memory != NULL; ) {
Memory* next = memory->next;
+#if !USE_FFI_ALLOC
freePage(memory->code);
+#else
+ ffi_closure_free(memory->code);
+#endif
free(memory->data);
free(memory);
memory = next;
@@ -134,6 +143,8 @@ rbffi_ClosurePool_Free(ClosurePool* pool)
}
}
+#if !USE_FFI_ALLOC
+
Closure*
rbffi_Closure_Alloc(ClosurePool* pool)
{
@@ -169,6 +180,7 @@ rbffi_Closure_Alloc(ClosurePool* pool)
closure->next = &list[i + 1];
closure->pool = pool;
closure->code = ((char *)code + (i * trampolineSize));
+ closure->pcl = closure->code;
if (!(*pool->prep)(pool->ctx, closure->code, closure, errmsg, sizeof(errmsg))) {
goto error;
@@ -205,6 +217,57 @@ error:
return NULL;
}
+#else
+
+Closure*
+rbffi_Closure_Alloc(ClosurePool* pool)
+{
+ Closure *closure = NULL;
+ Memory* block = NULL;
+ void *code = NULL;
+ void *pcl = NULL;
+ char errmsg[256];
+
+ block = calloc(1, sizeof(*block));
+ closure = calloc(1, sizeof(*closure));
+ pcl = ffi_closure_alloc(sizeof(ffi_closure), &code);
+
+ if (block == NULL || closure == NULL || pcl == NULL) {
+ snprintf(errmsg, sizeof(errmsg), "failed to allocate a page. errno=%d (%s)", errno, strerror(errno));
+ goto error;
+ }
+
+ closure->pool = pool;
+ closure->code = code;
+ closure->pcl = pcl;
+
+ if (!(*pool->prep)(pool->ctx, closure->code, closure, errmsg, sizeof(errmsg))) {
+ goto error;
+ }
+
+ /* Track the allocated page + Closure memory area */
+ block->data = closure;
+ block->code = pcl;
+ pool->blocks = block;
+
+ /* Thread the new block onto the free list, apart from the first one. */
+ pool->refcnt++;
+
+ return closure;
+
+error:
+ free(block);
+ free(closure);
+ if (pcl != NULL) {
+ ffi_closure_free(pcl);
+ }
+
+ rb_raise(rb_eRuntimeError, "%s", errmsg);
+ return NULL;
+}
+
+#endif /* !USE_FFI_ALLOC */
+
void
rbffi_Closure_Free(Closure* closure)
{
@@ -240,6 +303,8 @@ getPageSize()
#endif
}
+#if !USE_FFI_ALLOC
+
static void*
allocatePage(void)
{
@@ -272,6 +337,8 @@ protectPage(void* page)
#endif
}
+#endif /* !USE_FFI_ALLOC */
+
void
rbffi_ClosurePool_Init(VALUE module)
{
diff --git a/ext/ffi_c/ClosurePool.h b/ext/ffi_c/ClosurePool.h
index b842375..36619f4 100644
--- a/ext/ffi_c/ClosurePool.h
+++ b/ext/ffi_c/ClosurePool.h
@@ -36,6 +36,8 @@ struct Closure_ {
void* info; /* opaque handle for storing closure-instance specific data */
void* function; /* closure-instance specific function, called by custom trampoline */
void* code; /* The native trampoline code location */
+ void* pcl;
+
struct ClosurePool_* pool;
Closure* next;
};
diff --git a/ext/ffi_c/Function.c b/ext/ffi_c/Function.c
index 506d79b..b1d5a65 100644
--- a/ext/ffi_c/Function.c
+++ b/ext/ffi_c/Function.c
@@ -849,7 +849,7 @@ callback_prep(void* ctx, void* code, Closure* closure, char* errmsg, size_t errm
FunctionType* fnInfo = (FunctionType *) ctx;
ffi_status ffiStatus;
- ffiStatus = ffi_prep_closure_loc(code, &fnInfo->ffi_cif, callback_invoke, closure, code);
+ ffiStatus = ffi_prep_closure_loc(closure->pcl, &fnInfo->ffi_cif, callback_invoke, closure, code);
if (ffiStatus != FFI_OK) {
snprintf(errmsg, errmsgsize, "ffi_prep_closure_loc failed. status=%#x", ffiStatus);
return false;
diff --git a/ext/ffi_c/MethodHandle.c b/ext/ffi_c/MethodHandle.c
index 4dc85fb..bdd5632 100644
--- a/ext/ffi_c/MethodHandle.c
+++ b/ext/ffi_c/MethodHandle.c
@@ -140,7 +140,7 @@ prep_trampoline(void* ctx, void* code, Closure* closure, char* errmsg, size_t er
#if defined(USE_RAW)
ffiStatus = ffi_prep_raw_closure(code, &mh_cif, attached_method_invoke, closure);
#else
- ffiStatus = ffi_prep_closure_loc(code, &mh_cif, attached_method_invoke, closure, code);
+ ffiStatus = ffi_prep_closure_loc(closure->pcl, &mh_cif, attached_method_invoke, closure, code);
#endif
if (ffiStatus != FFI_OK) {
snprintf(errmsg, errmsgsize, "ffi_prep_closure_loc failed. status=%#x", ffiStatus);