summaryrefslogtreecommitdiff
path: root/ext/ffi_c/Call.c
diff options
context:
space:
mode:
authorLars Kanis <lars@greiz-reinsdorf.de>2017-07-26 20:59:06 +0200
committerLars Kanis <kanis@comcard.de>2019-01-25 09:00:02 +0100
commit547cfee7e9d2af4c45fc12953bd2791f05c84d8f (patch)
tree2efb394a12e170e5633e548a97d5225e6a6fc5ba /ext/ffi_c/Call.c
parent7592bfa9a449dd99670ad55234a1bc0f0c71416e (diff)
downloadffi-547cfee7e9d2af4c45fc12953bd2791f05c84d8f.tar.gz
Query ruby thread and GVL states instead of relying on our call frame for callbacks
This fixes #527 and other interoperability issues that can happen, when a callback is called without a valid call frame. The change is enabled for ruby-2.3+ only, since it requires the functions ruby_native_thread_p() and ruby_thread_has_gvl_p(). The creation of a call frame is not (yet) removed, because it still carries callback expections around.
Diffstat (limited to 'ext/ffi_c/Call.c')
-rw-r--r--ext/ffi_c/Call.c24
1 files changed, 14 insertions, 10 deletions
diff --git a/ext/ffi_c/Call.c b/ext/ffi_c/Call.c
index 0b9aceb..d0a7122 100644
--- a/ext/ffi_c/Call.c
+++ b/ext/ffi_c/Call.c
@@ -116,7 +116,7 @@ rbffi_SetupCallParams(int argc, VALUE* argv, int paramCount, Type** paramTypes,
Type* paramType = paramTypes[i];
int type;
-
+
if (unlikely(paramType->nativeType == NATIVE_MAPPED)) {
VALUE values[] = { argv[argidx], Qnil };
argv[argidx] = rb_funcall2(((MappedType *) paramType)->rbConverter, id_to_native, 2, values);
@@ -297,8 +297,8 @@ rbffi_SetupCallParams(int argc, VALUE* argv, int paramCount, Type** paramTypes,
case NATIVE_STRING:
if (type == T_NIL) {
- param->ptr = NULL;
-
+ param->ptr = NULL;
+
} else {
if (rb_safe_level() >= 1 && OBJ_TAINTED(argv[argidx])) {
rb_raise(rb_eSecurityError, "Unsafe string parameter");
@@ -345,9 +345,13 @@ static void *
call_blocking_function(void* data)
{
rbffi_blocking_call_t* b = (rbffi_blocking_call_t *) data;
+#ifndef HAVE_RUBY_THREAD_HAS_GVL_P
b->frame->has_gvl = false;
+#endif
ffi_call(&b->cif, FFI_FN(b->function), b->retval, b->ffiValues);
+#ifndef HAVE_RUBY_THREAD_HAS_GVL_P
b->frame->has_gvl = true;
+#endif
return NULL;
}
@@ -376,9 +380,9 @@ rbffi_CallFunction(int argc, VALUE* argv, void* function, FunctionType* fnInfo)
FFIStorage* params;
VALUE rbReturnValue;
rbffi_frame_t frame = { 0 };
-
+
retval = alloca(MAX(fnInfo->ffi_cif.rtype->size, FFI_SIZEOF_ARG));
-
+
if (unlikely(fnInfo->blocking)) {
rbffi_blocking_call_t* bc;
@@ -408,7 +412,7 @@ rbffi_CallFunction(int argc, VALUE* argv, void* function, FunctionType* fnInfo)
fnInfo->parameterCount, fnInfo->parameterTypes, params, ffiValues,
fnInfo->callbackParameters, fnInfo->callbackCount, fnInfo->rbEnums);
- rbffi_frame_push(&frame);
+ rbffi_frame_push(&frame);
rb_rescue2(rbffi_do_blocking_call, (VALUE) bc, rbffi_save_frame_exception, (VALUE) &frame, rb_eException, (VALUE) 0);
rbffi_frame_pop(&frame);
@@ -419,7 +423,7 @@ rbffi_CallFunction(int argc, VALUE* argv, void* function, FunctionType* fnInfo)
xfree(bc->retval);
xfree(bc);
#endif
-
+
} else {
ffiValues = ALLOCA_N(void *, fnInfo->parameterCount);
@@ -436,7 +440,7 @@ rbffi_CallFunction(int argc, VALUE* argv, void* function, FunctionType* fnInfo)
if (unlikely(!fnInfo->ignoreErrno)) {
rbffi_save_errno();
- }
+ }
if (RTEST(frame.exc) && frame.exc != Qnil) {
rb_exc_raise(frame.exc);
@@ -444,7 +448,7 @@ rbffi_CallFunction(int argc, VALUE* argv, void* function, FunctionType* fnInfo)
RB_GC_GUARD(rbReturnValue) = rbffi_NativeValue_ToRuby(fnInfo->returnType, fnInfo->rbReturnType, retval);
RB_GC_GUARD(fnInfo->rbReturnType);
-
+
return rbReturnValue;
}
@@ -461,7 +465,7 @@ getPointer(VALUE value, int type)
return memory != NULL ? memory->address : NULL;
} else if (type == T_STRING) {
-
+
return StringValuePtr(value);
} else if (type == T_NIL) {