]> granicus.if.org Git - php/commitdiff
Fixed incorrect recursion detection
authorDmitry Stogov <dmitry@zend.com>
Fri, 6 Oct 2017 08:47:11 +0000 (11:47 +0300)
committerDmitry Stogov <dmitry@zend.com>
Fri, 6 Oct 2017 08:47:11 +0000 (11:47 +0300)
Zend/zend_hash.c
Zend/zend_object_handlers.c
tests/lang/operators/operator_identical_recusion-01.phpt [new file with mode: 0644]

index 07dcd26e8d71d20a781400b7dbb4a0d649762caf..d629c098dcebcca5a26032647791efbb880c9ba9 100644 (file)
@@ -2369,24 +2369,21 @@ ZEND_API int zend_hash_compare(HashTable *ht1, HashTable *ht2, compare_func_t co
                return 0;
        }
 
-       /* use bitwise OR to make only one conditional jump */
-       if (UNEXPECTED(GC_IS_RECURSIVE(ht1) | GC_IS_RECURSIVE(ht2))) {
+       /* It's enough to protect only one of the arrays.
+        * The second one may be referenced from the first and this may cause
+        * false recursion detection.
+        */
+       if (UNEXPECTED(GC_IS_RECURSIVE(ht1))) {
                zend_error_noreturn(E_ERROR, "Nesting level too deep - recursive dependency?");
        }
 
        if (!(GC_FLAGS(ht1) & GC_IMMUTABLE)) {
                GC_PROTECT_RECURSION(ht1);
        }
-       if (!(GC_FLAGS(ht2) & GC_IMMUTABLE)) {
-               GC_PROTECT_RECURSION(ht2);
-       }
        result = zend_hash_compare_impl(ht1, ht2, compar, ordered);
        if (!(GC_FLAGS(ht1) & GC_IMMUTABLE)) {
                GC_UNPROTECT_RECURSION(ht1);
        }
-       if (!(GC_FLAGS(ht2) & GC_IMMUTABLE)) {
-               GC_UNPROTECT_RECURSION(ht2);
-       }
 
        return result;
 }
index f1412ef0d240d1dbff578ad82704e158e54ccf24..6e709cdfaa39ced1d80bffb247ae814912eb61d0 100644 (file)
@@ -1448,12 +1448,15 @@ static int zend_std_compare_objects(zval *o1, zval *o2) /* {{{ */
                p2 = zobj2->properties_table;
                end = p1 + zobj1->ce->default_properties_count;
 
+               /* It's enough to protect only one of the objects.
+                * The second one may be referenced from the first and this may cause
+                * false recursion detection.
+                */
                /* use bitwise OR to make only one conditional jump */
-               if (UNEXPECTED(Z_IS_RECURSIVE_P(o1) | Z_IS_RECURSIVE_P(o2))) {
+               if (UNEXPECTED(Z_IS_RECURSIVE_P(o1))) {
                        zend_error_noreturn(E_ERROR, "Nesting level too deep - recursive dependency?");
                }
                Z_PROTECT_RECURSION_P(o1);
-               Z_PROTECT_RECURSION_P(o2);
                do {
                        if (Z_TYPE_P(p1) != IS_UNDEF) {
                                if (Z_TYPE_P(p2) != IS_UNDEF) {
@@ -1461,23 +1464,19 @@ static int zend_std_compare_objects(zval *o1, zval *o2) /* {{{ */
 
                                        if (compare_function(&result, p1, p2)==FAILURE) {
                                                Z_UNPROTECT_RECURSION_P(o1);
-                                               Z_UNPROTECT_RECURSION_P(o2);
                                                return 1;
                                        }
                                        if (Z_LVAL(result) != 0) {
                                                Z_UNPROTECT_RECURSION_P(o1);
-                                               Z_UNPROTECT_RECURSION_P(o2);
                                                return Z_LVAL(result);
                                        }
                                } else {
                                        Z_UNPROTECT_RECURSION_P(o1);
-                                       Z_UNPROTECT_RECURSION_P(o2);
                                        return 1;
                                }
                        } else {
                                if (Z_TYPE_P(p2) != IS_UNDEF) {
                                        Z_UNPROTECT_RECURSION_P(o1);
-                                       Z_UNPROTECT_RECURSION_P(o2);
                                        return 1;
                                }
                        }
@@ -1485,7 +1484,6 @@ static int zend_std_compare_objects(zval *o1, zval *o2) /* {{{ */
                        p2++;
                } while (p1 != end);
                Z_UNPROTECT_RECURSION_P(o1);
-               Z_UNPROTECT_RECURSION_P(o2);
                return 0;
        } else {
                if (!zobj1->properties) {
diff --git a/tests/lang/operators/operator_identical_recusion-01.phpt b/tests/lang/operators/operator_identical_recusion-01.phpt
new file mode 100644 (file)
index 0000000..3680e30
--- /dev/null
@@ -0,0 +1,10 @@
+--TEST--
+Test === operator : False recursion detection
+--FILE--
+<?php
+$n = 0;
+$a = [[$n]];
+$b = [&$a];
+var_dump($a === $b);
+--EXPECT--
+bool(false)
\ No newline at end of file