summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorXinchen Hui <laruence@gmail.com>2016-04-09 10:01:04 -0700
committerXinchen Hui <laruence@gmail.com>2016-04-09 10:01:04 -0700
commit5db4d9a71c1510921f1d5514d1e1d4bf53200eae (patch)
treeca081ecccc9e07b54222e584437f0203176d98f0
parentef17343b3cb9195437d760ec21dcdf6004a85b67 (diff)
downloadphp-git-5db4d9a71c1510921f1d5514d1e1d4bf53200eae.tar.gz
Fixed bug #71995 (Returning the same var twice from __sleep() produces broken serialized data)
-rw-r--r--NEWS2
-rw-r--r--ext/standard/tests/serialize/bug71995.phpt27
-rw-r--r--ext/standard/var.c66
3 files changed, 75 insertions, 20 deletions
diff --git a/NEWS b/NEWS
index 57faa19739..1c0a5cd106 100644
--- a/NEWS
+++ b/NEWS
@@ -84,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, '}');
}
/* }}} */