]> granicus.if.org Git - php/commitdiff
Fixed bug #70685
authorNikita Popov <nikic@php.net>
Sat, 10 Oct 2015 12:54:14 +0000 (14:54 +0200)
committerNikita Popov <nikic@php.net>
Sat, 10 Oct 2015 12:59:21 +0000 (14:59 +0200)
Doing a less intrusive variant of the PHP 7.0 fix for 5.6.

NEWS
Zend/tests/bug70685.phpt [new file with mode: 0644]
Zend/zend_closures.c

diff --git a/NEWS b/NEWS
index 90369ebce48c264b33e1c300328b214a7cc62476..ca695467fb6746c18f71d5bb48e5cd077f096236 100644 (file)
--- 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 (file)
index 0000000..e286e58
--- /dev/null
@@ -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
index 582a1f77841f11174d37a5c1d7cd5d956f1dd6a6..f57d6b509d9da8655f9835067af17cee4780cb78 100644 (file)
@@ -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;