]> granicus.if.org Git - php/commitdiff
Fixed bug #76901
authorNikita Popov <nikita.ppv@gmail.com>
Wed, 19 Sep 2018 07:37:04 +0000 (09:37 +0200)
committerNikita Popov <nikita.ppv@gmail.com>
Wed, 19 Sep 2018 07:37:04 +0000 (09:37 +0200)
get_method() may modify the object pointer passed to it if method
forwarding is used. In this case we do not want to modify the
passed zval, so make sure that we copy the object into a temporary
first.

NEWS
Zend/tests/bug76901.phpt [new file with mode: 0644]
Zend/zend_builtin_functions.c

diff --git a/NEWS b/NEWS
index 0e5daeacd6adab8eb36bbcafef814115d82c005a..1add82df498b50150e82f4643ba3df113c7a71d8 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -2,6 +2,10 @@ PHP                                                                        NEWS
 |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
 ?? ??? 2018, PHP 7.1.23
 
+- Core:
+  . Fixed bug #76901 (method_exists on SPL iterator passthrough method corrupts
+    memory). (Nikita)
+
 - CURL:
   . Fixed bug #76480 (Use curl_multi_wait() so that timeouts are respected).
     (Pierrick)
diff --git a/Zend/tests/bug76901.phpt b/Zend/tests/bug76901.phpt
new file mode 100644 (file)
index 0000000..8d567d9
--- /dev/null
@@ -0,0 +1,18 @@
+--TEST--
+Bug #76901: method_exists on SPL iterator passthrough method corrupts memory
+--FILE--
+<?php
+
+$it = new ArrayIterator([1, 2, 3]);
+$it = new IteratorIterator($it);
+foreach ($it as $v) {
+    if (method_exists($it, 'offsetGet')) {
+        var_dump($it->offsetGet(0));
+    }
+}
+
+?>
+--EXPECT--
+int(1)
+int(1)
+int(1)
index 184b352ec83b24097a9033f8001abae1a3b56846..f792756a11de45fb2ab09db65dfe41e300410952 100644 (file)
@@ -1400,13 +1400,10 @@ ZEND_FUNCTION(method_exists)
        if (zend_hash_exists(&ce->function_table, lcname)) {
                zend_string_release(lcname);
                RETURN_TRUE;
-       } else {
-               union _zend_function *func = NULL;
-
-               if (Z_TYPE_P(klass) == IS_OBJECT
-               && Z_OBJ_HT_P(klass)->get_method != NULL
-               && (func = Z_OBJ_HT_P(klass)->get_method(&Z_OBJ_P(klass), method_name, NULL)) != NULL
-               ) {
+       } else if (Z_TYPE_P(klass) == IS_OBJECT && Z_OBJ_HT_P(klass)->get_method != NULL) {
+               zend_object *obj = Z_OBJ_P(klass);
+               zend_function *func = Z_OBJ_HT_P(klass)->get_method(&obj, method_name, NULL);
+               if (func != NULL) {
                        if (func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) {
                                /* Returns true to the fake Closure's __invoke */
                                RETVAL_BOOL(func->common.scope == zend_ce_closure