diff --git a/ext/ffi/ffi.c b/ext/ffi/ffi.c index 9be5ac340590c..8f5f488ced55a 100644 --- a/ext/ffi/ffi.c +++ b/ext/ffi/ffi.c @@ -2148,7 +2148,6 @@ static zend_result zend_ffi_cdata_get_closure(zend_object *obj, zend_class_entry func->common.arg_flags[0] = 0; func->common.arg_flags[1] = 0; func->common.arg_flags[2] = 0; - func->common.fn_flags = ZEND_ACC_CALL_VIA_TRAMPOLINE; func->common.function_name = ZSTR_KNOWN(ZEND_STR_MAGIC_INVOKE); /* set to 0 to avoid arg_info[] allocation, because all values are passed by value anyway */ func->common.num_args = 0; @@ -2161,6 +2160,7 @@ static zend_result zend_ffi_cdata_get_closure(zend_object *obj, zend_class_entry func->internal_function.reserved[0] = type; func->internal_function.reserved[1] = *(void**)cdata->ptr; + func->internal_function.reserved[2] = func; *ce_ptr = NULL; *fptr_ptr= func; @@ -2843,8 +2843,9 @@ static ZEND_FUNCTION(ffi_trampoline) /* {{{ */ exit: zend_string_release(EX(func)->common.function_name); - if (EX(func)->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) { - zend_free_trampoline(EX(func)); + zend_function *func = EX(func)->internal_function.reserved[2]; + if (func) { + zend_free_trampoline(func); EX(func) = NULL; } } @@ -2899,7 +2900,6 @@ static zend_function *zend_ffi_get_func(zend_object **obj, zend_string *name, co func->common.arg_flags[0] = 0; func->common.arg_flags[1] = 0; func->common.arg_flags[2] = 0; - func->common.fn_flags = ZEND_ACC_CALL_VIA_TRAMPOLINE; func->common.function_name = zend_string_copy(name); /* set to 0 to avoid arg_info[] allocation, because all values are passed by value anyway */ func->common.num_args = 0; @@ -2912,6 +2912,7 @@ static zend_function *zend_ffi_get_func(zend_object **obj, zend_string *name, co func->internal_function.reserved[0] = type; func->internal_function.reserved[1] = sym->addr; + func->internal_function.reserved[2] = func; return func; } diff --git a/ext/ffi/tests/bug79177.phpt b/ext/ffi/tests/bug79177.phpt index aaabfdbca012f..9ee3f1ec377d5 100644 --- a/ext/ffi/tests/bug79177.phpt +++ b/ext/ffi/tests/bug79177.phpt @@ -32,7 +32,7 @@ echo "done\n"; --EXPECTF-- Warning: Uncaught RuntimeException: Not allowed in %s:%d Stack trace: -#0 %s(%d): {closure}() +#0 [internal function]: {closure}() #1 %s(%d): FFI->bug79177() #2 {main} thrown in %s on line %d diff --git a/ext/ffi/tests/first_class_callable.phpt b/ext/ffi/tests/first_class_callable.phpt new file mode 100644 index 0000000000000..c5e60ef5b1bd1 --- /dev/null +++ b/ext/ffi/tests/first_class_callable.phpt @@ -0,0 +1,27 @@ +--TEST-- +Bug: Cannot create first-class callable from CData function +--EXTENSIONS-- +ffi +--SKIPIF-- + +--INI-- +ffi.enable=1 +--FILE-- +printf("Hello world\n"); +$closure = $libc->printf; +$closure("%s %s\n", "Hello", "world"); +$closure = $libc->printf(...); +$closure("%s %s\n", "Hello", "world"); +?> +--EXPECT-- +Hello world +Hello world +Hello world