diff options
author | Dmitry Stogov <dmitry@zend.com> | 2015-10-09 18:41:15 +0200 |
---|---|---|
committer | Nikita Popov <nikic@php.net> | 2015-10-12 20:34:08 +0200 |
commit | 23b372d358577c8146e4c35e936413e5a43043d9 (patch) | |
tree | e932502c6718d85a991e56b66ce5bf7ddea3f0df | |
parent | dcbbf7c38d45fd06752b7298ed765733ca2f8d41 (diff) | |
download | php-git-23b372d358577c8146e4c35e936413e5a43043d9.tar.gz |
Forbid "fake" closure rebinding
-rw-r--r-- | Zend/tests/bug70630.phpt | 2 | ||||
-rw-r--r-- | Zend/zend_closures.c | 21 | ||||
-rw-r--r-- | Zend/zend_closures.h | 1 | ||||
-rw-r--r-- | ext/reflection/php_reflection.c | 6 |
4 files changed, 21 insertions, 9 deletions
diff --git a/Zend/tests/bug70630.phpt b/Zend/tests/bug70630.phpt index fc79949ce2..d78ee62c6a 100644 --- a/Zend/tests/bug70630.phpt +++ b/Zend/tests/bug70630.phpt @@ -7,4 +7,4 @@ $x = (new ReflectionFunction("substr"))->getClosure(); $x->call(new a); ?> --EXPECTF-- -Warning: a::substr() expects at least 2 parameters, 0 given in %s on line %d +Warning: Cannot rebind scope of closure created by ReflectionFunctionAbstract::getClosure() in %s on line %d diff --git a/Zend/zend_closures.c b/Zend/zend_closures.c index b1e21ed1e4..76b10e43d3 100644 --- a/Zend/zend_closures.c +++ b/Zend/zend_closures.c @@ -34,6 +34,9 @@ #define ZEND_CLOSURE_PROPERTY_ERROR() \ zend_throw_error(NULL, "Closure object cannot have properties") +/* reuse bit to mark "fake" closures (it wasn't used for functions before) */ +#define ZEND_ACC_FAKE_CLOSURE ZEND_ACC_INTERFACE + typedef struct _zend_closure { zend_object std; zend_function func; @@ -102,11 +105,8 @@ static zend_bool zend_valid_closure_binding( return 0; } - if (func->type == ZEND_INTERNAL_FUNCTION && scope && func->common.scope && - !instanceof_function(scope, func->common.scope)) { - zend_error(E_WARNING, "Cannot bind function %s::%s to scope class %s", - ZSTR_VAL(func->common.scope->name), ZSTR_VAL(func->common.function_name), - ZSTR_VAL(scope->name)); + if ((func->common.fn_flags & ZEND_ACC_FAKE_CLOSURE) && scope != func->common.scope) { + zend_error(E_WARNING, "Cannot rebind scope of closure created by ReflectionFunctionAbstract::getClosure()"); return 0; } @@ -617,6 +617,17 @@ ZEND_API void zend_create_closure(zval *res, zend_function *func, zend_class_ent } /* }}} */ +ZEND_API void zend_create_fake_closure(zval *res, zend_function *func, zend_class_entry *scope, zend_class_entry *called_scope, zval *this_ptr) /* {{{ */ +{ + zend_closure *closure; + + zend_create_closure(res, func, scope, called_scope, this_ptr); + + closure = (zend_closure *)Z_OBJ_P(res); + closure->func.common.fn_flags |= ZEND_ACC_FAKE_CLOSURE; +} +/* }}} */ + /* * Local variables: * tab-width: 4 diff --git a/Zend/zend_closures.h b/Zend/zend_closures.h index 8d0963ec17..8d4edfd37a 100644 --- a/Zend/zend_closures.h +++ b/Zend/zend_closures.h @@ -29,6 +29,7 @@ void zend_register_closure_ce(void); extern ZEND_API zend_class_entry *zend_ce_closure; ZEND_API void zend_create_closure(zval *res, zend_function *op_array, zend_class_entry *scope, zend_class_entry *called_scope, zval *this_ptr); +ZEND_API void zend_create_fake_closure(zval *res, zend_function *op_array, zend_class_entry *scope, zend_class_entry *called_scope, zval *this_ptr); ZEND_API zend_function *zend_get_closure_invoke_method(zend_object *obj); ZEND_API const zend_function *zend_get_closure_method_def(zval *obj); ZEND_API zval* zend_get_closure_this_ptr(zval *obj); diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index 00731c70c3..a095120e18 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -1762,7 +1762,7 @@ ZEND_METHOD(reflection_function, getClosure) } GET_REFLECTION_OBJECT_PTR(fptr); - zend_create_closure(return_value, fptr, NULL, NULL, NULL); + zend_create_fake_closure(return_value, fptr, NULL, NULL, NULL); } /* }}} */ @@ -3144,7 +3144,7 @@ ZEND_METHOD(reflection_method, getClosure) GET_REFLECTION_OBJECT_PTR(mptr); if (mptr->common.fn_flags & ZEND_ACC_STATIC) { - zend_create_closure(return_value, mptr, mptr->common.scope, mptr->common.scope, NULL); + zend_create_fake_closure(return_value, mptr, mptr->common.scope, mptr->common.scope, NULL); } else { if (zend_parse_parameters(ZEND_NUM_ARGS(), "o", &obj) == FAILURE) { return; @@ -3161,7 +3161,7 @@ ZEND_METHOD(reflection_method, getClosure) { ZVAL_COPY(return_value, obj); } else { - zend_create_closure(return_value, mptr, mptr->common.scope, Z_OBJCE_P(obj), obj); + zend_create_fake_closure(return_value, mptr, mptr->common.scope, Z_OBJCE_P(obj), obj); } } } |