]> granicus.if.org Git - php/commitdiff
Add check_only parameter to get_closure handler
authorChristoph M. Becker <cmbecker69@gmx.de>
Mon, 23 Sep 2019 21:48:36 +0000 (23:48 +0200)
committerChristoph M. Becker <cmbecker69@gmx.de>
Tue, 24 Sep 2019 14:08:42 +0000 (16:08 +0200)
`get_closure` handlers are called to check whether an object is
callable, and to actually get the closure, respectively.  The behavior
of the handler might differ for these two cases, particularly the
handler may throw in the latter case, but should not in the former.

Therefore we add a `check_only` parameter, to be able to distinguish
the desired purpose.

Zend/zend_API.c
Zend/zend_closures.c
Zend/zend_execute.c
Zend/zend_object_handlers.c
Zend/zend_object_handlers.h
ext/ffi/ffi.c
ext/reflection/php_reflection.c

index 472d88646726c0827c106552b71460a15f6b6ce9..34fcf1506a2cbf357f220fb40ca432e924809da3 100644 (file)
@@ -3105,7 +3105,7 @@ try_again:
                        zend_object *zobj = Z_OBJ_P(callable);
 
                        if (zobj->handlers->get_closure
-                                       && zobj->handlers->get_closure(zobj, &calling_scope, &fptr, &object) == SUCCESS) {
+                                       && zobj->handlers->get_closure(zobj, &calling_scope, &fptr, &object, 1) == SUCCESS) {
                                zend_class_entry *ce = zobj->ce;
                                zend_string *callable_name = zend_string_alloc(
                                        ZSTR_LEN(ce->name) + sizeof("::__invoke") - 1, 0);
@@ -3230,18 +3230,12 @@ check_func:
                        }
                        return 0;
                case IS_OBJECT:
-                       if (Z_OBJ_HANDLER_P(callable, get_closure)) {
-                               if (Z_OBJ_HANDLER_P(callable, get_closure)(Z_OBJ_P(callable), &fcc->calling_scope, &fcc->function_handler, &fcc->object) == SUCCESS) {
+                       if (Z_OBJ_HANDLER_P(callable, get_closure) && Z_OBJ_HANDLER_P(callable, get_closure)(Z_OBJ_P(callable), &fcc->calling_scope, &fcc->function_handler, &fcc->object, 1) == SUCCESS) {
                                fcc->called_scope = fcc->calling_scope;
                                if (fcc == &fcc_local) {
                                        zend_release_fcall_info_cache(fcc);
                                }
                                return 1;
-                               } else {
-                                       /* Discard exceptions thrown from Z_OBJ_HANDLER_P(callable, get_closure)
-                                          TODO: extend get_closure() with additional argument and prevent exception throwing in the first place */
-                                       zend_clear_exception();
-                       }
                        }
                        if (error) *error = estrdup("no array or string given");
                        return 0;
index d6cb6abc7a21622bfbdc73ff6b545d35c78043ae..68e698b62622215dcb0174ed58c721d73745f0b0 100644 (file)
@@ -490,7 +490,7 @@ static zend_object *zend_closure_clone(zend_object *zobject) /* {{{ */
 }
 /* }}} */
 
-int zend_closure_get_closure(zend_object *obj, zend_class_entry **ce_ptr, zend_function **fptr_ptr, zend_object **obj_ptr) /* {{{ */
+int zend_closure_get_closure(zend_object *obj, zend_class_entry **ce_ptr, zend_function **fptr_ptr, zend_object **obj_ptr, zend_bool check_only) /* {{{ */
 {
        zend_closure *closure = (zend_closure *)obj;
        *fptr_ptr = &closure->func;
index 2c3ed7e5aeb539ffa4fdf482207e1fdc26f75d9d..2c7b9f50307e1160145158399574b825b36e7842 100644 (file)
@@ -3956,7 +3956,7 @@ static zend_never_inline zend_execute_data *zend_init_dynamic_call_object(zend_o
        uint32_t call_info = ZEND_CALL_NESTED_FUNCTION | ZEND_CALL_DYNAMIC;
 
        if (EXPECTED(function->handlers->get_closure) &&
-           EXPECTED(function->handlers->get_closure(function, &called_scope, &fbc, &object) == SUCCESS)) {
+           EXPECTED(function->handlers->get_closure(function, &called_scope, &fbc, &object, 0) == SUCCESS)) {
 
            object_or_called_scope = called_scope;
                if (fbc->common.fn_flags & ZEND_ACC_CLOSURE) {
index 6530913174640f4d7255936096fd59ca88133339..f60083d85811e425052f1060d5d1a917c9e60124 100644 (file)
@@ -1767,7 +1767,7 @@ ZEND_API int zend_std_cast_object_tostring(zend_object *readobj, zval *writeobj,
 }
 /* }}} */
 
-ZEND_API int zend_std_get_closure(zend_object *obj, zend_class_entry **ce_ptr, zend_function **fptr_ptr, zend_object **obj_ptr) /* {{{ */
+ZEND_API int zend_std_get_closure(zend_object *obj, zend_class_entry **ce_ptr, zend_function **fptr_ptr, zend_object **obj_ptr, zend_bool check_only) /* {{{ */
 {
        zval *func;
        zend_class_entry *ce = obj->ce;
index 05ebb0b1ef2dcf0c110a260d807417405c976033..d8d7aca86c5b8ad40bde7a31fe2afc674c95dca6 100644 (file)
@@ -135,7 +135,7 @@ typedef int (*zend_object_cast_t)(zend_object *readobj, zval *retval, int type);
  * Returns FAILURE if the object does not have any sense of overloaded dimensions */
 typedef int (*zend_object_count_elements_t)(zend_object *object, zend_long *count);
 
-typedef int (*zend_object_get_closure_t)(zend_object *obj, zend_class_entry **ce_ptr, zend_function **fptr_ptr, zend_object **obj_ptr);
+typedef int (*zend_object_get_closure_t)(zend_object *obj, zend_class_entry **ce_ptr, zend_function **fptr_ptr, zend_object **obj_ptr, zend_bool check_only);
 
 typedef HashTable *(*zend_object_get_gc_t)(zend_object *object, zval **table, int *n);
 
@@ -208,7 +208,7 @@ ZEND_API void zend_std_unset_dimension(zend_object *object, zval *offset);
 ZEND_API zend_function *zend_std_get_method(zend_object **obj_ptr, zend_string *method_name, const zval *key);
 ZEND_API zend_string *zend_std_get_class_name(const zend_object *zobj);
 ZEND_API int zend_std_compare_objects(zval *o1, zval *o2);
-ZEND_API int zend_std_get_closure(zend_object *obj, zend_class_entry **ce_ptr, zend_function **fptr_ptr, zend_object **obj_ptr);
+ZEND_API int zend_std_get_closure(zend_object *obj, zend_class_entry **ce_ptr, zend_function **fptr_ptr, zend_object **obj_ptr, zend_bool check_only);
 ZEND_API void rebuild_object_properties(zend_object *zobj);
 
 ZEND_API int zend_check_protected(zend_class_entry *ce, zend_class_entry *scope);
index aae8b3ab2168202b1dff3bc48c6d9d9e7f178715..c3fbc112bfac16d3ab7a0cdb1bb9c18274e40ad1 100644 (file)
@@ -1984,23 +1984,29 @@ static HashTable *zend_ffi_cdata_get_debug_info(zend_object *obj, int *is_temp)
 }
 /* }}} */
 
-static int zend_ffi_cdata_get_closure(zend_object *obj, zend_class_entry **ce_ptr, zend_function **fptr_ptr, zend_object **obj_ptr) /* {{{ */
+static int zend_ffi_cdata_get_closure(zend_object *obj, zend_class_entry **ce_ptr, zend_function **fptr_ptr, zend_object **obj_ptr, zend_bool check_only) /* {{{ */
 {
        zend_ffi_cdata *cdata = (zend_ffi_cdata*)obj;
        zend_ffi_type  *type = ZEND_FFI_TYPE(cdata->type);
        zend_function  *func;
 
        if (type->kind != ZEND_FFI_TYPE_POINTER) {
-               zend_throw_error(zend_ffi_exception_ce, "Attempt to call non C function pointer");
+               if (!check_only) {
+                       zend_throw_error(zend_ffi_exception_ce, "Attempt to call non C function pointer");
+               }
                return FAILURE;
        }
        type = ZEND_FFI_TYPE(type->pointer.type);
        if (type->kind != ZEND_FFI_TYPE_FUNC) {
-               zend_throw_error(zend_ffi_exception_ce, "Attempt to call non C function pointer");
+               if (!check_only) {
+                       zend_throw_error(zend_ffi_exception_ce, "Attempt to call non C function pointer");
+               }
                return FAILURE;
        }
        if (!cdata->ptr) {
-               zend_throw_error(zend_ffi_exception_ce, "NULL pointer dereference");
+               if (!check_only) {
+                       zend_throw_error(zend_ffi_exception_ce, "NULL pointer dereference");
+               }
                return FAILURE;
        }
 
index a6aa982f0d796d12acf9cc3323a49197b3612bf4..5c775ed926d151a36cec2ff4be35f07fc4b0c935 100644 (file)
@@ -1794,7 +1794,7 @@ ZEND_METHOD(reflection_function, invoke)
 
        if (!Z_ISUNDEF(intern->obj)) {
                Z_OBJ_HT(intern->obj)->get_closure(
-                       Z_OBJ(intern->obj), &fcc.called_scope, &fcc.function_handler, &fcc.object);
+                       Z_OBJ(intern->obj), &fcc.called_scope, &fcc.function_handler, &fcc.object, 0);
        }
 
        result = zend_call_function(&fci, &fcc);
@@ -1857,7 +1857,7 @@ ZEND_METHOD(reflection_function, invokeArgs)
 
        if (!Z_ISUNDEF(intern->obj)) {
                Z_OBJ_HT(intern->obj)->get_closure(
-                       Z_OBJ(intern->obj), &fcc.called_scope, &fcc.function_handler, &fcc.object);
+                       Z_OBJ(intern->obj), &fcc.called_scope, &fcc.function_handler, &fcc.object, 0);
        }
 
        result = zend_call_function(&fci, &fcc);