summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitry Stogov <dmitry@zend.com>2013-01-09 11:32:40 +0400
committerDmitry Stogov <dmitry@zend.com>2013-01-09 11:32:40 +0400
commit326f896739785cfcd36ef918dbd399ac605f6552 (patch)
tree2a710fd908ad52afeeb56c1064bbc08cd76cd6c9
parent6deb8361f32d14fffdd284b47b59cd5dd50baf80 (diff)
parentf9e8678dd3a41ed8a100d8201153a41d6fd25f2e (diff)
downloadphp-git-326f896739785cfcd36ef918dbd399ac605f6552.tar.gz
Merge branch 'PHP-5.4' into PHP-5.5
* PHP-5.4: Fixed bug #63882 (zend_std_compare_objects crash on recursion) Conflicts: NEWS
-rw-r--r--Zend/tests/bug63882.phpt15
-rw-r--r--Zend/zend_object_handlers.c26
-rw-r--r--Zend/zend_objects_API.c1
-rw-r--r--Zend/zend_objects_API.h1
4 files changed, 43 insertions, 0 deletions
diff --git a/Zend/tests/bug63882.phpt b/Zend/tests/bug63882.phpt
new file mode 100644
index 0000000000..0cc1babd49
--- /dev/null
+++ b/Zend/tests/bug63882.phpt
@@ -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
diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c
index a76dfb38ac..3881c0e870 100644
--- a/Zend/zend_object_handlers.c
+++ b/Zend/zend_object_handlers.c
@@ -35,6 +35,17 @@
#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) {
diff --git a/Zend/zend_objects_API.c b/Zend/zend_objects_API.c
index 4f3561e3d7..1fe5d0c199 100644
--- a/Zend/zend_objects_API.c
+++ b/Zend/zend_objects_API.c
@@ -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);
diff --git a/Zend/zend_objects_API.h b/Zend/zend_objects_API.h
index c973b7a20c..a6ea9b8c02 100644
--- a/Zend/zend_objects_API.h
+++ b/Zend/zend_objects_API.h
@@ -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;