]> granicus.if.org Git - php/commitdiff
Enforce ordering of property compare in object comparisons
authorSara Golemon <pollita@php.net>
Sat, 11 Aug 2018 15:19:28 +0000 (11:19 -0400)
committerSara Golemon <pollita@php.net>
Mon, 10 Sep 2018 12:47:50 +0000 (08:47 -0400)
Zend/tests/objects_033.phpt [new file with mode: 0644]
Zend/zend_object_handlers.c

diff --git a/Zend/tests/objects_033.phpt b/Zend/tests/objects_033.phpt
new file mode 100644 (file)
index 0000000..365edc3
--- /dev/null
@@ -0,0 +1,27 @@
+--TEST--
+Ensure object comparison property order remains consistent
+--FILE--
+<?php
+
+// PHP4-5.3 object semantics had child properties added to an
+// object HashTable first, then parent, then grandparent, etc...
+// As of PHP 5.4 we use a packed C array to hold properties
+// which may or may not share the same ordering.
+// In the code snippet below, the print_r() has the side-effect
+// of materializing the properties shadow HashTable which
+// if used for comparison, results in the behavior consistent
+// with pre PHP-5.4.
+// This test ensures that the first comparison yields the same
+// result without shadow table materialization.
+
+class A { public $a; }
+class B extends A { public $b; }
+$a = new B(); $a->a = 0; $a->b = 1;
+$b = new B(); $b->a = 1; $b->b = 0;
+
+var_dump($a < $b);
+print_r($a, true);
+var_dump($a < $b);
+--EXPECT--
+bool(false)
+bool(false)
index fde7b1204cfcbc56a32956698bd44cf3d556d610..aa2f5be8465c5cbdbbf565f1d5c31f0589d11f6d 100644 (file)
@@ -1514,14 +1514,11 @@ ZEND_API int zend_std_compare_objects(zval *o1, zval *o2) /* {{{ */
                return 1; /* different classes */
        }
        if (!zobj1->properties && !zobj2->properties) {
-               zval *p1, *p2, *end;
+               zend_property_info *info;
 
                if (!zobj1->ce->default_properties_count) {
                        return 0;
                }
-               p1 = zobj1->properties_table;
-               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
@@ -1532,7 +1529,15 @@ ZEND_API int zend_std_compare_objects(zval *o1, zval *o2) /* {{{ */
                        zend_error_noreturn(E_ERROR, "Nesting level too deep - recursive dependency?");
                }
                Z_PROTECT_RECURSION_P(o1);
-               do {
+
+               ZEND_HASH_FOREACH_PTR(&zobj1->ce->properties_info, info) {
+                       zval *p1 = OBJ_PROP(zobj1, info->offset);
+                       zval *p2 = OBJ_PROP(zobj2, info->offset);
+
+                       if (info->flags & ZEND_ACC_STATIC) {
+                               continue;
+                       }
+
                        if (Z_TYPE_P(p1) != IS_UNDEF) {
                                if (Z_TYPE_P(p2) != IS_UNDEF) {
                                        zval result;
@@ -1555,9 +1560,8 @@ ZEND_API int zend_std_compare_objects(zval *o1, zval *o2) /* {{{ */
                                        return 1;
                                }
                        }
-                       p1++;
-                       p2++;
-               } while (p1 != end);
+               } ZEND_HASH_FOREACH_END();
+
                Z_UNPROTECT_RECURSION_P(o1);
                return 0;
        } else {