summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikita Popov <nikic@php.net>2015-10-10 14:54:14 +0200
committerNikita Popov <nikic@php.net>2015-10-10 14:59:21 +0200
commitd7d01fc9a326fe530df4e067db1df9ec451f4411 (patch)
tree81f063e63da780ea4b9f263ed4eba56bd344c80b
parente19423f3cbeaf2ac57a4af1e7c5b84fc6721177b (diff)
downloadphp-git-d7d01fc9a326fe530df4e067db1df9ec451f4411.tar.gz
Fixed bug #70685
Doing a less intrusive variant of the PHP 7.0 fix for 5.6.
-rw-r--r--NEWS2
-rw-r--r--Zend/tests/bug70685.phpt22
-rw-r--r--Zend/zend_closures.c27
3 files changed, 38 insertions, 13 deletions
diff --git a/NEWS b/NEWS
index 90369ebce4..ca695467fb 100644
--- a/NEWS
+++ b/NEWS
@@ -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;