diff options
author | Lars Kanis <lars@greiz-reinsdorf.de> | 2017-07-26 20:59:06 +0200 |
---|---|---|
committer | Lars Kanis <kanis@comcard.de> | 2019-01-25 09:00:02 +0100 |
commit | 547cfee7e9d2af4c45fc12953bd2791f05c84d8f (patch) | |
tree | 2efb394a12e170e5633e548a97d5225e6a6fc5ba /ext/ffi_c/Call.c | |
parent | 7592bfa9a449dd99670ad55234a1bc0f0c71416e (diff) | |
download | ffi-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.c | 24 |
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) { |