]> granicus.if.org Git - php/commitdiff
Special-case rc=1 self-referential arrays in ReflectionReference
authorNikita Popov <nikita.ppv@gmail.com>
Mon, 22 Jul 2019 14:59:23 +0000 (16:59 +0200)
committerNikita Popov <nikita.ppv@gmail.com>
Mon, 22 Jul 2019 14:59:23 +0000 (16:59 +0200)
New fix for bug #78263. This is special-cased elsewhere in the engine,
so we need to mirror it here.

ext/reflection/php_reflection.c
ext/reflection/tests/ReflectionReference_bug78263.phpt [new file with mode: 0644]

index dcb98b0653b6d6f7248ba2fbf06b8711d521dcfe..4011d8954e2cfdee3d74cae54b3ac34ae432f6ed 100644 (file)
@@ -6143,6 +6143,16 @@ ZEND_METHOD(reflection_reference, __construct)
 }
 /* }}} */
 
+static zend_bool is_ignorable_reference(HashTable *ht, zval *ref) {
+       if (Z_REFCOUNT_P(ref) != 1) {
+               return 0;
+       }
+
+       /* Directly self-referential arrays are treated as proper references
+        * in zend_array_dup() despite rc=1. */
+       return Z_TYPE_P(Z_REFVAL_P(ref)) != IS_ARRAY || Z_ARRVAL_P(Z_REFVAL_P(ref)) != ht;
+}
+
 /* {{{ proto public ReflectionReference|null ReflectionReference::fromArrayElement(array array, mixed key)
  *     Create ReflectionReference for array item. Returns null if not a reference. */
 ZEND_METHOD(reflection_reference, fromArrayElement)
@@ -6169,8 +6179,7 @@ ZEND_METHOD(reflection_reference, fromArrayElement)
                return;
        }
 
-       /* Treat singleton reference as non-reference. */
-       if (Z_TYPE_P(item) != IS_REFERENCE || Z_REFCOUNT_P(item) == 1) {
+       if (Z_TYPE_P(item) != IS_REFERENCE || is_ignorable_reference(ht, item)) {
                RETURN_NULL();
        }
 
diff --git a/ext/reflection/tests/ReflectionReference_bug78263.phpt b/ext/reflection/tests/ReflectionReference_bug78263.phpt
new file mode 100644 (file)
index 0000000..868edc0
--- /dev/null
@@ -0,0 +1,17 @@
+--TEST--
+Bug #78263: Handling of self-referential array special case
+--FILE--
+<?php
+
+// The case of a directly self-referential array is special and will
+// be treated as a proper reference despite rc=1 during array copying.
+$a = [&$a];
+$b = [$a];
+unset($a);
+
+var_dump(ReflectionReference::fromArrayElement($b[0], 0));
+
+?>
+--EXPECT--
+object(ReflectionReference)#1 (0) {
+}