diff options
author | Nikita Popov <nikic@php.net> | 2015-10-10 14:54:14 +0200 |
---|---|---|
committer | Nikita Popov <nikic@php.net> | 2015-10-10 14:59:21 +0200 |
commit | d7d01fc9a326fe530df4e067db1df9ec451f4411 (patch) | |
tree | 81f063e63da780ea4b9f263ed4eba56bd344c80b | |
parent | e19423f3cbeaf2ac57a4af1e7c5b84fc6721177b (diff) | |
download | php-git-d7d01fc9a326fe530df4e067db1df9ec451f4411.tar.gz |
Fixed bug #70685
Doing a less intrusive variant of the PHP 7.0 fix for 5.6.
-rw-r--r-- | NEWS | 2 | ||||
-rw-r--r-- | Zend/tests/bug70685.phpt | 22 | ||||
-rw-r--r-- | Zend/zend_closures.c | 27 |
3 files changed, 38 insertions, 13 deletions
@@ -5,6 +5,8 @@ PHP NEWS - Core: . Fixed bug #70681 (Segfault when binding $this of internal instance method to null). (Nikita) + . Fixed bug #70685 (Segfault for getClosure() internal method rebind with + invalid $this). (Nikita) - Date: . Fixed bug #70619 (DateTimeImmutable segfault). (Laruence) diff --git a/Zend/tests/bug70685.phpt b/Zend/tests/bug70685.phpt new file mode 100644 index 0000000000..e286e58e7d --- /dev/null +++ b/Zend/tests/bug70685.phpt @@ -0,0 +1,22 @@ +--TEST-- +Bug #70685: Segfault for getClosure() internal method rebind with invalid $this +--FILE-- +<?php + +class cls {} + +$c = (new ReflectionMethod('SplStack', 'count'))->getClosure(new SplStack); +$c = $c->bindTo(new cls); +var_dump($c); + +$c = (new ReflectionMethod('SplStack', 'count'))->getClosure(new SplStack); +$c = $c->bindTo(new SplStack, 'cls'); +var_dump($c); + +?> +--EXPECTF-- +Warning: Cannot bind internal method SplDoublyLinkedList::count() to object of class cls in %s on line %d +NULL + +Warning: Cannot bind function SplDoublyLinkedList::count to scope class cls in %s on line %d +NULL diff --git a/Zend/zend_closures.c b/Zend/zend_closures.c index 582a1f7784..f57d6b509d 100644 --- a/Zend/zend_closures.c +++ b/Zend/zend_closures.c @@ -133,6 +133,19 @@ ZEND_METHOD(Closure, bind) ce = closure->func.common.scope; } + /* verify that we aren't binding internal function to a wrong scope */ + if (closure->func.type == ZEND_INTERNAL_FUNCTION && closure->func.common.scope != NULL) { + if (ce && !instanceof_function(ce, closure->func.common.scope TSRMLS_CC)) { + zend_error(E_WARNING, "Cannot bind function %s::%s to scope class %s", closure->func.common.scope->name, closure->func.common.function_name, ce->name); + return; + } + if (ce && newthis && (closure->func.common.fn_flags & ZEND_ACC_STATIC) == 0 && + !instanceof_function(Z_OBJCE_P(newthis), closure->func.common.scope TSRMLS_CC)) { + zend_error(E_WARNING, "Cannot bind internal method %s::%s() to object of class %s", closure->func.common.scope->name, closure->func.common.function_name, Z_OBJCE_P(newthis)->name); + return; + } + } + zend_create_closure(return_value, &closure->func, ce, newthis TSRMLS_CC); } /* }}} */ @@ -470,19 +483,7 @@ ZEND_API void zend_create_closure(zval *res, zend_function *func, zend_class_ent closure->func.op_array.run_time_cache = NULL; (*closure->func.op_array.refcount)++; } else { - /* verify that we aren't binding internal function to a wrong scope */ - if(func->common.scope != NULL) { - if(scope && !instanceof_function(scope, func->common.scope TSRMLS_CC)) { - zend_error(E_WARNING, "Cannot bind function %s::%s to scope class %s", func->common.scope->name, func->common.function_name, scope->name); - scope = NULL; - } - if(scope && this_ptr && (func->common.fn_flags & ZEND_ACC_STATIC) == 0 && - !instanceof_function(Z_OBJCE_P(this_ptr), closure->func.common.scope TSRMLS_CC)) { - zend_error(E_WARNING, "Cannot bind function %s::%s to object of class %s", func->common.scope->name, func->common.function_name, Z_OBJCE_P(this_ptr)->name); - scope = NULL; - this_ptr = NULL; - } - } else { + if (!func->common.scope) { /* if it's a free function, we won't set scope & this since they're meaningless */ this_ptr = NULL; scope = NULL; |