From e2d6090043aed271d18a4d157cbb64138481c9ed Mon Sep 17 00:00:00 2001 From: Xinchen Hui Date: Sat, 17 Oct 2015 05:28:49 -0700 Subject: [PATCH] Fixed bug #70730 (Incorrect ArrayObject serialization if unset is called in serialize()) It's possible to fixed this in SPL side, but it will be ugly, and we should make serialize more robust, so I prefer fix it in serialize side. --- NEWS | 12 ++++++---- ext/spl/tests/bug70730.phpt | 44 +++++++++++++++++++++++++++++++++++++ ext/standard/var.c | 30 ++++++++++++------------- 3 files changed, 67 insertions(+), 19 deletions(-) create mode 100644 ext/spl/tests/bug70730.phpt diff --git a/NEWS b/NEWS index 29bb0e41df..6343dc6db5 100644 --- a/NEWS +++ b/NEWS @@ -6,14 +6,18 @@ PHP NEWS . Fixed bug #70689 (Exception handler does not work as expected). (Laruence) . Fixed bug #70430 (Stack buffer overflow in zend_language_parser()). (Nikita) -- SOAP: - . Fixed bug #70715 (Segmentation fault inside soap client). (Laruence) - . Fixed bug #70709 (SOAP Client generates Segfault). (Laruence) - - Opcache: . Fixed bug #70724 (Undefined Symbols from opcache.so on Mac OS X 10.10). (Laruence) +- SPL: + . Fixed bug #70730 (Incorrect ArrayObject serialization if unset is called + in serialize()). (Laruence) + +- SOAP: + . Fixed bug #70715 (Segmentation fault inside soap client). (Laruence) + . Fixed bug #70709 (SOAP Client generates Segfault). (Laruence) + - XSL: . Fixed bug #70678 (PHP7 returns true when false is expected). (Felipe) diff --git a/ext/spl/tests/bug70730.phpt b/ext/spl/tests/bug70730.phpt new file mode 100644 index 0000000000..5710c9586d --- /dev/null +++ b/ext/spl/tests/bug70730.phpt @@ -0,0 +1,44 @@ +--TEST-- +Bug #70730 (Incorrect ArrayObject serialization if unset is called in serialize()) +--FILE-- +foo = 'bar'; + } + + public function serialize() + { + unset($this->foo); + $result = parent::serialize(); + $this->foo = 'bar'; + return $result; + } +} + +$a = new A(); +$a->append('item1'); +$a->append('item2'); +$a->append('item3'); +$b = new A(); +$b->unserialize($a->serialize()); +var_dump($b); +?> +--EXPECTF-- +object(A)#%d (2) { + ["foo":protected]=> + string(3) "bar" + ["storage":"ArrayObject":private]=> + array(3) { + [0]=> + string(5) "item1" + [1]=> + string(5) "item2" + [2]=> + string(5) "item3" + } +} diff --git a/ext/standard/var.c b/ext/standard/var.c index 5de32f9c3e..72b2dd5ed5 100644 --- a/ext/standard/var.c +++ b/ext/standard/var.c @@ -35,7 +35,7 @@ #define COMMON (is_ref ? "&" : "") /* }}} */ -static uint32_t zend_hash_recalc_elements(HashTable *ht) /* {{{ */ +static uint32_t php_array_recalc_elements(HashTable *ht) /* {{{ */ { zval *val; uint32_t num = ht->nNumOfElements; @@ -52,12 +52,12 @@ static uint32_t zend_hash_recalc_elements(HashTable *ht) /* {{{ */ } /* }}} */ -static uint32_t zend_obj_num_elements(HashTable *ht) /* {{{ */ +static uint32_t php_array_num_elements(HashTable *ht) /* {{{ */ { uint32_t num = ht->nNumOfElements; if (UNEXPECTED(ht->u.v.flags & HASH_FLAG_HAS_EMPTY_IND)) { - num = zend_hash_recalc_elements(ht); + num = php_array_recalc_elements(ht); if (UNEXPECTED(ht->nNumOfElements == num)) { ht->u.v.flags &= ~HASH_FLAG_HAS_EMPTY_IND; } @@ -151,9 +151,9 @@ again: return; } if (UNEXPECTED(Z_SYMBOLTABLE_P(struc))) { - count = zend_hash_recalc_elements(myht); + count = php_array_recalc_elements(myht); } else { - count = zend_hash_num_elements(myht); + count = php_array_num_elements(myht); } php_printf("%sarray(%d) {\n", COMMON, count); is_temp = 0; @@ -182,7 +182,7 @@ again: myht = Z_OBJDEBUG_P(struc, is_temp); class_name = Z_OBJ_HANDLER_P(struc, get_class_name)(Z_OBJ_P(struc)); - php_printf("%sobject(%s)#%d (%d) {\n", COMMON, ZSTR_VAL(class_name), Z_OBJ_HANDLE_P(struc), myht ? zend_obj_num_elements(myht) : 0); + php_printf("%sobject(%s)#%d (%d) {\n", COMMON, ZSTR_VAL(class_name), Z_OBJ_HANDLE_P(struc), myht ? php_array_num_elements(myht) : 0); zend_string_release(class_name); if (myht) { @@ -325,9 +325,9 @@ again: return; } if (UNEXPECTED(Z_SYMBOLTABLE_P(struc))) { - count = zend_hash_recalc_elements(myht); + count = php_array_recalc_elements(myht); } else { - count = zend_hash_num_elements(myht); + count = php_array_num_elements(myht); } php_printf("%sarray(%d) refcount(%u){\n", COMMON, count, Z_REFCOUNTED_P(struc) ? Z_REFCOUNT_P(struc) : 1); ZEND_HASH_FOREACH_KEY_VAL_IND(myht, index, key, val) { @@ -356,7 +356,7 @@ again: } } class_name = Z_OBJ_HANDLER_P(struc, get_class_name)(Z_OBJ_P(struc)); - php_printf("%sobject(%s)#%d (%d) refcount(%u){\n", COMMON, ZSTR_VAL(class_name), Z_OBJ_HANDLE_P(struc), myht ? zend_obj_num_elements(myht) : 0, Z_REFCOUNT_P(struc)); + php_printf("%sobject(%s)#%d (%d) refcount(%u){\n", COMMON, ZSTR_VAL(class_name), Z_OBJ_HANDLE_P(struc), myht ? php_array_num_elements(myht) : 0, Z_REFCOUNT_P(struc)); zend_string_release(class_name); if (myht) { ZEND_HASH_FOREACH_KEY_VAL_IND(myht, index, key, val) { @@ -708,13 +708,13 @@ static void php_var_serialize_class(smart_str *buf, zval *struc, zval *retval_pt if (Z_TYPE_P(retval_ptr) == IS_ARRAY) { ht = Z_ARRVAL_P(retval_ptr); if (UNEXPECTED(Z_SYMBOLTABLE_P(struc))) { - count = zend_hash_recalc_elements(ht); + count = php_array_recalc_elements(ht); } else { - count = zend_hash_num_elements(ht); + count = php_array_num_elements(ht); } } else if (Z_TYPE_P(retval_ptr) == IS_OBJECT) { ht = Z_OBJPROP_P(retval_ptr); - count = zend_obj_num_elements(ht); + count = php_array_num_elements(ht); if (incomplete_class) { --count; } @@ -936,16 +936,16 @@ again: smart_str_appendl(buf, "a:", 2); myht = Z_ARRVAL_P(struc); if (UNEXPECTED(Z_SYMBOLTABLE_P(struc))) { - i = zend_hash_recalc_elements(myht); + i = php_array_recalc_elements(myht); } else { - i = zend_hash_num_elements(myht); + i = php_array_num_elements(myht); } } else { incomplete_class = php_var_serialize_class_name(buf, struc); myht = Z_OBJPROP_P(struc); /* count after serializing name, since php_var_serialize_class_name * changes the count if the variable is incomplete class */ - i = zend_obj_num_elements(myht); + i = php_array_num_elements(myht); if (i > 0 && incomplete_class) { --i; } -- 2.40.0