]> granicus.if.org Git - php/commitdiff
Fix ref handling in array_merge/replace_recursive()
authorNikita Popov <nikic@php.net>
Fri, 29 Jul 2016 17:07:04 +0000 (19:07 +0200)
committerNikita Popov <nikic@php.net>
Fri, 29 Jul 2016 17:07:04 +0000 (19:07 +0200)
As usual, if the reference has rc=1 it really isn't a reference.

ext/standard/array.c
ext/standard/tests/array/array_merge_replace_recursive_refs.phpt [new file with mode: 0644]

index e5c38f2906523514f14248652ba4c00047b7087b..538460bdcc85b1f589632d2a0a061a71da38763d 100644 (file)
@@ -3075,16 +3075,12 @@ PHPAPI int php_array_merge_recursive(HashTable *dest, HashTable *src) /* {{{ */
                                }
                                zval_ptr_dtor(&tmp);
                        } else {
-                               if (Z_REFCOUNTED_P(src_entry)) {
-                                       Z_ADDREF_P(src_entry);
-                               }
-                               zend_hash_add_new(dest, string_key, src_entry);
+                               zval *zv = zend_hash_add_new(dest, string_key, src_entry);
+                               zval_add_ref(zv);
                        }
                } else {
-                       if (Z_REFCOUNTED_P(src_entry)) {
-                               Z_ADDREF_P(src_entry);
-                       }
-                       zend_hash_next_index_insert_new(dest, src_entry);
+                       zval *zv = zend_hash_next_index_insert_new(dest, src_entry);
+                       zval_add_ref(zv);
                }
        } ZEND_HASH_FOREACH_END();
        return 1;
@@ -3134,11 +3130,8 @@ PHPAPI int php_array_replace_recursive(HashTable *dest, HashTable *src) /* {{{ *
                                (Z_TYPE_P(dest_entry) != IS_ARRAY &&
                                 (!Z_ISREF_P(dest_entry) || Z_TYPE_P(Z_REFVAL_P(dest_entry)) != IS_ARRAY))) {
 
-                               if (Z_REFCOUNTED_P(src_entry)) {
-                                       Z_ADDREF_P(src_entry);
-                               }
-                               zend_hash_update(dest, string_key, src_entry);
-
+                               zval *zv = zend_hash_update(dest, string_key, src_entry);
+                               zval_add_ref(zv);
                                continue;
                        }
                } else {
@@ -3147,11 +3140,8 @@ PHPAPI int php_array_replace_recursive(HashTable *dest, HashTable *src) /* {{{ *
                                (Z_TYPE_P(dest_entry) != IS_ARRAY &&
                                 (!Z_ISREF_P(dest_entry) || Z_TYPE_P(Z_REFVAL_P(dest_entry)) != IS_ARRAY))) {
 
-                               if (Z_REFCOUNTED_P(src_entry)) {
-                                       Z_ADDREF_P(src_entry);
-                               }
-                               zend_hash_index_update(dest, num_key, src_entry);
-
+                               zval *zv = zend_hash_index_update(dest, num_key, src_entry);
+                               zval_add_ref(zv);
                                continue;
                        }
                }
diff --git a/ext/standard/tests/array/array_merge_replace_recursive_refs.phpt b/ext/standard/tests/array/array_merge_replace_recursive_refs.phpt
new file mode 100644 (file)
index 0000000..ac8be2b
--- /dev/null
@@ -0,0 +1,38 @@
+--TEST--
+array_merge/replace_recursive() should unwrap references with rc=1
+--FILE--
+<?php
+
+$x = 24;
+$arr1 = [[42]];
+$arr2 = [[&$x]];
+unset($x);
+$arr3 = array_replace_recursive($arr1, $arr2);
+$arr2[0][0] = 12;
+var_dump($arr3);
+
+unset($arr1, $arr2, $arr3);
+
+$x = 24;
+$arr1 = [42];
+$arr2 = [&$x];
+unset($x);
+$arr3 = array_merge_recursive($arr1, $arr2);
+$arr2[0] = 12;
+var_dump($arr3);
+
+?>
+--EXPECT--
+array(1) {
+  [0]=>
+  array(1) {
+    [0]=>
+    int(24)
+  }
+}
+array(2) {
+  [0]=>
+  int(42)
+  [1]=>
+  int(24)
+}