]> granicus.if.org Git - php/commitdiff
Fixed bug #71995 (Returning the same var twice from __sleep() produces broken seriali...
authorXinchen Hui <laruence@gmail.com>
Sat, 9 Apr 2016 17:01:04 +0000 (10:01 -0700)
committerXinchen Hui <laruence@gmail.com>
Sat, 9 Apr 2016 17:01:04 +0000 (10:01 -0700)
NEWS
ext/standard/tests/serialize/bug71995.phpt [new file with mode: 0644]
ext/standard/var.c

diff --git a/NEWS b/NEWS
index 57faa1973935dfe68b50d5d6bc9e159ad22c37a7..1c0a5cd106e944d6ee5f4472341d26ddda3b9ad9 100644 (file)
--- 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 (file)
index 0000000..0f7ac98
--- /dev/null
@@ -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) {
+  }
+}
index ca621dd8a4d51801a29eca9f128c3fe0436b3a70..acb1d40c0171c2699035913aa63d153b64ca5270 100644 (file)
@@ -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, '}');
 }
 /* }}} */