diff options
-rw-r--r-- | NEWS | 4 | ||||
-rw-r--r-- | ext/standard/tests/serialize/bug71995.phpt | 27 | ||||
-rw-r--r-- | ext/standard/var.c | 66 |
3 files changed, 75 insertions, 22 deletions
@@ -43,8 +43,6 @@ PHP NEWS . Fixed bug #70451, #70452 (Inconsistencies in return values of IntlChar methods). (Daniel Persson) . Fixed bug #68893 (Stackoverflow in datefmt_create). (Anatol) - . Fixed bug #66289 (Locale::lookup incorrectly returns en or en_US if - locale is empty). (Anatol) - ODBC: . Fixed bug #63171 (Script hangs after max_execution_time). (Remi) @@ -86,6 +84,8 @@ PHP NEWS . Fixed bug #52339 (SPL autoloader breaks class_exists()). (Nikita) - Standard: + . Fixed bug #71995 (Returning the same var twice from __sleep() produces + broken serialized data). (Laruence) . Fixed bug #71940 (Unserialize crushes on restore object reference). (Laruence) . Fixed bug #71969 (str_replace returns an incorrect resulting array after diff --git a/ext/standard/tests/serialize/bug71995.phpt b/ext/standard/tests/serialize/bug71995.phpt new file mode 100644 index 0000000000..0f7ac98722 --- /dev/null +++ b/ext/standard/tests/serialize/bug71995.phpt @@ -0,0 +1,27 @@ +--TEST-- +Bug #71995 (Returning the same var twice from __sleep() produces broken serialized data) +--FILE-- +<?php + +class A { + public $b; + public function __construct() { + $this->b = new StdClass(); + } + public function __sleep() { + return array("b", "b"); + } +} +$a = new A(); +$s = serialize($a); +var_dump($s); +var_dump(unserialize($s)); +?> +--EXPECTF-- +Notice: serialize(): "b" is returned from __sleep multiple times in %sbug71995.php on line %d +string(39) "O:1:"A":1:{s:1:"b";O:8:"stdClass":0:{}}" +object(A)#%d (1) { + ["b"]=> + object(stdClass)#%d (0) { + } +} diff --git a/ext/standard/var.c b/ext/standard/var.c index ca621dd8a4..acb1d40c01 100644 --- a/ext/standard/var.c +++ b/ext/standard/var.c @@ -666,6 +666,36 @@ static inline zend_bool php_var_serialize_class_name(smart_str *buf, zval *struc } /* }}} */ +static HashTable *php_var_serialize_collect_names(HashTable *src, uint32_t count, zend_bool incomplete) /* {{{ */ { + zval *val; + HashTable *ht; + zend_string *key, *name; + + ALLOC_HASHTABLE(ht); + zend_hash_init(ht, count, NULL, NULL, 0); + ZEND_HASH_FOREACH_STR_KEY_VAL(src, key, val) { + if (incomplete && strcmp(ZSTR_VAL(key), MAGIC_MEMBER) == 0) { + continue; + } + if (Z_TYPE_P(val) != IS_STRING) { + php_error_docref(NULL, E_NOTICE, + "__sleep should return an array only containing the names of instance-variables to serialize."); + } + name = zval_get_string(val); + if (zend_hash_exists(ht, name)) { + php_error_docref(NULL, E_NOTICE, + "\"%s\" is returned from __sleep multiple times", ZSTR_VAL(name)); + zend_string_release(name); + continue; + } + zend_hash_add_empty_element(ht, name); + zend_string_release(name); + } ZEND_HASH_FOREACH_END(); + + return ht; +} +/* }}} */ + static void php_var_serialize_class(smart_str *buf, zval *struc, zval *retval_ptr, php_serialize_data_t var_hash) /* {{{ */ { uint32_t count; @@ -686,37 +716,29 @@ static void php_var_serialize_class(smart_str *buf, zval *struc, zval *retval_pt } } else { count = 0; + ht = NULL; } - smart_str_append_unsigned(buf, count); - smart_str_appendl(buf, ":{", 2); - if (count > 0) { - zend_string *key; - zval *d, *val; + zval *d; zval nval, *nvalp; zend_string *name; - HashTable *propers; + HashTable *names, *propers; + + names = php_var_serialize_collect_names(ht, count, incomplete_class); + + smart_str_append_unsigned(buf, zend_hash_num_elements(names)); + smart_str_appendl(buf, ":{", 2); ZVAL_NULL(&nval); nvalp = &nval; + propers = Z_OBJPROP_P(struc); - ZEND_HASH_FOREACH_STR_KEY_VAL(ht, key, val) { - if (incomplete_class && strcmp(ZSTR_VAL(key), MAGIC_MEMBER) == 0) { - continue; - } - - if (Z_TYPE_P(val) != IS_STRING) { - php_error_docref(NULL, E_NOTICE, - "__sleep should return an array only containing the names of instance-variables to serialize."); - } - name = zval_get_string(val); - propers = Z_OBJPROP_P(struc); + ZEND_HASH_FOREACH_STR_KEY(names, name) { if ((d = zend_hash_find(propers, name)) != NULL) { if (Z_TYPE_P(d) == IS_INDIRECT) { d = Z_INDIRECT_P(d); if (Z_TYPE_P(d) == IS_UNDEF) { - zend_string_release(name); continue; } } @@ -769,10 +791,14 @@ static void php_var_serialize_class(smart_str *buf, zval *struc, zval *retval_pt php_var_serialize_intern(buf, nvalp, var_hash); } } - zend_string_release(name); } ZEND_HASH_FOREACH_END(); + smart_str_appendc(buf, '}'); + + zend_hash_destroy(names); + FREE_HASHTABLE(names); + } else { + smart_str_appendl(buf, "0:{}", 4); } - smart_str_appendc(buf, '}'); } /* }}} */ |