]> granicus.if.org Git - php/commitdiff
Fixed bug #63882 (zend_std_compare_objects crash on recursion)
authorDmitry Stogov <dmitry@zend.com>
Wed, 9 Jan 2013 07:30:50 +0000 (11:30 +0400)
committerDmitry Stogov <dmitry@zend.com>
Wed, 9 Jan 2013 07:30:50 +0000 (11:30 +0400)
NEWS
Zend/tests/bug63882.phpt [new file with mode: 0644]
Zend/zend_object_handlers.c
Zend/zend_objects_API.c
Zend/zend_objects_API.h

diff --git a/NEWS b/NEWS
index 1abd3981a1e045eefef429df4a72ed164e91bb2a..cfc0fa994b769cd5cc55bc62810310e0206e08e7 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -5,6 +5,7 @@ PHP                                                                        NEWS
 - Core:
   . Fixed bug #63943 (Bad warning text from strpos() on empty needle).
     (Laruence)
+  . Fixed bug #63882 (zend_std_compare_objects crash on recursion). (Dmitry)
 
 - Litespeed:
   . Fixed bug #63228 (-Werror=format-security error in lsapi code). (George)
diff --git a/Zend/tests/bug63882.phpt b/Zend/tests/bug63882.phpt
new file mode 100644 (file)
index 0000000..0cc1bab
--- /dev/null
@@ -0,0 +1,15 @@
+--TEST--
+Bug #63882 (zend_std_compare_objects crash on recursion)
+--FILE--
+<?php
+class Test { public $x = 5; }
+
+$testobj1 = new Test;
+$testobj2 = new Test;
+$testobj1->x = $testobj1;
+$testobj2->x = $testobj2;
+
+var_dump($testobj1 == $testobj2);
+?>
+--EXPECTF--
+Fatal error: Nesting level too deep - recursive dependency? in %sbug63882.php on line 9
index a76dfb38acc4c7d5072182b540f58c65a08e2e8b..3881c0e8708d9dd46537685f227aee92246ffcc9 100644 (file)
 #define Z_OBJ_P(zval_p) \
        ((zend_object*)(EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(zval_p)].bucket.obj.object))
 
+#define Z_OBJ_PROTECT_RECURSION(zval_p) \
+       do { \
+               if (EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(zval_p)].apply_count++ >= 3) { \
+                       zend_error(E_ERROR, "Nesting level too deep - recursive dependency?"); \
+               } \
+       } while (0)
+
+
+#define Z_OBJ_UNPROTECT_RECURSION(zval_p) \
+       EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(zval_p)].apply_count--
+
 /*
   __X accessors explanation:
 
@@ -1319,28 +1330,43 @@ static int zend_std_compare_objects(zval *o1, zval *o2 TSRMLS_DC) /* {{{ */
        }
        if (!zobj1->properties && !zobj2->properties) {
                int i;
+
+               Z_OBJ_PROTECT_RECURSION(o1);
+               Z_OBJ_PROTECT_RECURSION(o2);
                for (i = 0; i < zobj1->ce->default_properties_count; i++) {
                        if (zobj1->properties_table[i]) {
                                if (zobj2->properties_table[i]) {
                                        zval result;
 
                                        if (compare_function(&result, zobj1->properties_table[i], zobj2->properties_table[i] TSRMLS_CC)==FAILURE) {
+                                               Z_OBJ_UNPROTECT_RECURSION(o1);
+                                               Z_OBJ_UNPROTECT_RECURSION(o2);
                                                return 1;
                                        }
                                        if (Z_LVAL(result) != 0) {
+                                               Z_OBJ_UNPROTECT_RECURSION(o1);
+                                               Z_OBJ_UNPROTECT_RECURSION(o2);
                                                return Z_LVAL(result);
                                        }
                                } else {
+                                       Z_OBJ_UNPROTECT_RECURSION(o1);
+                                       Z_OBJ_UNPROTECT_RECURSION(o2);
                                        return 1;
                                }
                        } else {
                                if (zobj2->properties_table[i]) {
+                                       Z_OBJ_UNPROTECT_RECURSION(o1);
+                                       Z_OBJ_UNPROTECT_RECURSION(o2);
                                        return 1;
                                } else {
+                                       Z_OBJ_UNPROTECT_RECURSION(o1);
+                                       Z_OBJ_UNPROTECT_RECURSION(o2);
                                        return 0;
                                }
                        }
                }
+               Z_OBJ_UNPROTECT_RECURSION(o1);
+               Z_OBJ_UNPROTECT_RECURSION(o2);
                return 0;
        } else {
                if (!zobj1->properties) {
index 4f3561e3d774de8adf7efea4d5ce7d8b1d16f3a0..1fe5d0c1994cd14d52ae35f9fbe529ec678596c5 100644 (file)
@@ -117,6 +117,7 @@ ZEND_API zend_object_handle zend_objects_store_put(void *object, zend_objects_st
        obj = &EG(objects_store).object_buckets[handle].bucket.obj;
        EG(objects_store).object_buckets[handle].destructor_called = 0;
        EG(objects_store).object_buckets[handle].valid = 1;
+       EG(objects_store).object_buckets[handle].apply_count = 0;
 
        obj->refcount = 1;
        GC_OBJ_INIT(obj);
index c973b7a20c3fcc0480280f9b50078b8d83847b43..a6ea9b8c02dfe49d167b001a326e42c9bffdb142 100644 (file)
@@ -31,6 +31,7 @@ typedef void (*zend_objects_store_clone_t)(void *object, void **object_clone TSR
 typedef struct _zend_object_store_bucket {
        zend_bool destructor_called;
        zend_bool valid;
+       zend_uchar apply_count;
        union _store_bucket {
                struct _store_object {
                        void *object;