From ef8bb69a147c19780d9e35ecfda8394e5e6ca1d2 Mon Sep 17 00:00:00 2001 From: Stanislav Malyshev Date: Mon, 27 Apr 2015 21:43:43 -0700 Subject: [PATCH] Ban rebinding closures to different internal classes --- Zend/tests/closure_call.phpt | 10 ++++++---- Zend/zend_closures.c | 16 +++++++++++++++- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/Zend/tests/closure_call.phpt b/Zend/tests/closure_call.phpt index d53b6077ee..e8bed36aec 100644 --- a/Zend/tests/closure_call.phpt +++ b/Zend/tests/closure_call.phpt @@ -42,7 +42,7 @@ $beta = function ($z) { }; // Ensure argument passing works -var_dump($beta->call($elePHPant, 3)); +var_dump($beta->call($foobar, 7)); // Ensure ->call calls with scope of passed object class FooBar { @@ -56,10 +56,12 @@ $foo = function () { $foo->call(new FooBar); ?> ---EXPECT-- +--EXPECTF-- int(0) int(0) int(3) -int(7) + +Warning: Cannot bind closure to object of internal class stdClass in %s line %d +NULL int(21) -int(3) \ No newline at end of file +int(3) diff --git a/Zend/zend_closures.c b/Zend/zend_closures.c index ec63f48884..e656f8d6ca 100644 --- a/Zend/zend_closures.c +++ b/Zend/zend_closures.c @@ -80,6 +80,7 @@ ZEND_METHOD(Closure, call) zval *my_params; int my_param_count = 0; zend_function my_function; + zend_object *newobj; if (zend_parse_parameters(ZEND_NUM_ARGS(), "o*", &newthis, &my_params, &my_param_count) == FAILURE) { return; @@ -102,6 +103,14 @@ ZEND_METHOD(Closure, call) } } + newobj = Z_OBJ_P(newthis); + + if (newobj->ce != closure->func.common.scope && newobj->ce->type == ZEND_INTERNAL_CLASS) { + /* rebinding to internal class is not allowed */ + zend_error(E_WARNING, "Cannot bind closure to object of internal class %s", newobj->ce->name->val); + return; + } + /* This should never happen as closures will always be callable */ if (zend_fcall_info_init(zclosure, 0, &fci, &fci_cache, NULL, NULL) != SUCCESS) { ZEND_ASSERT(0); @@ -110,7 +119,7 @@ ZEND_METHOD(Closure, call) fci.retval = &closure_result; fci.params = my_params; fci.param_count = my_param_count; - fci.object = fci_cache.object = Z_OBJ_P(newthis); + fci.object = fci_cache.object = newobj; fci_cache.initialized = 1; my_function = *fci_cache.function_handler; @@ -158,6 +167,11 @@ ZEND_METHOD(Closure, bind) } zend_string_release(class_name); } + if(ce && ce != closure->func.common.scope && ce->type == ZEND_INTERNAL_CLASS) { + /* rebinding to internal class is not allowed */ + zend_error(E_WARNING, "Cannot bind closure to scope of internal class %s", ce->name->val); + return; + } } else { /* scope argument not given; do not change the scope by default */ ce = closure->func.common.scope; } -- 2.40.0