]> granicus.if.org Git - php/commitdiff
Fix counting of "R:" references in serialize()
authorNikita Popov <nikic@php.net>
Wed, 24 Sep 2014 09:58:13 +0000 (11:58 +0200)
committerNikita Popov <nikic@php.net>
Wed, 24 Sep 2014 10:06:19 +0000 (12:06 +0200)
ext/standard/tests/serialize/counting_of_references.phpt [new file with mode: 0644]
ext/standard/var.c

diff --git a/ext/standard/tests/serialize/counting_of_references.phpt b/ext/standard/tests/serialize/counting_of_references.phpt
new file mode 100644 (file)
index 0000000..e7ead96
--- /dev/null
@@ -0,0 +1,14 @@
+--TEST--
+References are not counted twice
+--FILE--
+<?php
+
+$ref1 = 1;
+$ref2 = 2;
+
+$arr = [&$ref1, &$ref1, &$ref2, &$ref2];
+var_dump(serialize($arr));
+
+?>
+--EXPECT--
+string(38) "a:4:{i:0;i:1;i:1;R:2;i:2;i:2;i:3;R:3;}"
index 194715edf053692ad3725ad67e7a75ca48731852..53fd54c647f0953195f5e67ca5ce8cf40de71fad 100644 (file)
@@ -604,15 +604,16 @@ static inline uint32_t php_add_var_hash(php_serialize_data_t data, zval *var TSR
 {
        zval *zv;
        zend_ulong key;
+       zend_bool is_ref = Z_ISREF_P(var);
 
        data->n += 1;
 
-       if (Z_TYPE_P(var) != IS_OBJECT && Z_TYPE_P(var) != IS_REFERENCE) {
+       if (!is_ref && Z_TYPE_P(var) != IS_OBJECT) {
                return 0;
        }
 
        /* References to objects are treated as if the reference didn't exist */
-       if (Z_TYPE_P(var) == IS_REFERENCE && Z_TYPE_P(Z_REFVAL_P(var)) == IS_OBJECT) {
+       if (is_ref && Z_TYPE_P(Z_REFVAL_P(var)) == IS_OBJECT) {
                var = Z_REFVAL_P(var);
        }
 
@@ -622,6 +623,11 @@ static inline uint32_t php_add_var_hash(php_serialize_data_t data, zval *var TSR
        zv = zend_hash_index_find(&data->ht, key);
 
        if (zv) {
+               /* References are only counted once, undo the data->n increment above */
+               if (is_ref) {
+                       data->n -= 1;
+               }
+
                return Z_LVAL_P(zv);
        } else {
                zval zv_n;