Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,10 @@ PHP NEWS
. Fix ReflectionProperty::isReadable() not working for indirect slots.
(ndossche)

- SPL:
. Fixed bug GH-25404 (Missing zend_return_unwrap_ref() calls trigger
assertion failures). (Juan Versolato Lopes)

- Standard:
. Fixed bug GH-25387 (Uploaded files leak in request_parse_body()).
(Kévin Dunglas)
Expand Down
9 changes: 9 additions & 0 deletions ext/spl/spl_iterators.c
Original file line number Diff line number Diff line change
Expand Up @@ -825,6 +825,9 @@ PHP_METHOD(RecursiveIteratorIterator, callHasChildren)
if (Z_TYPE_P(return_value) == IS_UNDEF) {
RETURN_FALSE;
}
if (Z_ISREF_P(return_value)) {
zend_unwrap_reference(return_value);
}
}
} /* }}} */

Expand All @@ -847,6 +850,9 @@ PHP_METHOD(RecursiveIteratorIterator, callGetChildren)
if (Z_TYPE_P(return_value) == IS_UNDEF) {
RETURN_NULL();
}
if (Z_ISREF_P(return_value)) {
zend_unwrap_reference(return_value);
}
}
} /* }}} */

Expand Down Expand Up @@ -1672,6 +1678,9 @@ PHP_METHOD(RecursiveFilterIterator, hasChildren)
SPL_FETCH_AND_CHECK_DUAL_IT(intern, ZEND_THIS);

zend_call_method_with_0_params(Z_OBJ(intern->inner.zobject), intern->inner.ce, NULL, "haschildren", return_value);
if (Z_ISREF_P(return_value)) {
zend_unwrap_reference(return_value);
}
} /* }}} */

/* {{{ Return the inner iterator's children contained in a RecursiveFilterIterator */
Expand Down
42 changes: 42 additions & 0 deletions ext/spl/tests/gh25404.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
--TEST--
GH-25404 (SPL methods forward by-reference returns of user methods)
--FILE--
<?php

class Demo implements RecursiveIterator {
public mixed $hasChildren = true;
public mixed $children = null;

public function &getChildren(): ?RecursiveIterator { return $this->children; }
public function &hasChildren(): bool { return $this->hasChildren; }

public function current(): mixed { return null; }
public function key(): mixed { return null; }
public function next(): void {}
public function rewind(): void {}
public function valid(): bool { return true; }
}

class Filter extends RecursiveFilterIterator {
public function accept(): bool { return true; }
}

$demo = new Demo();

$it = new RecursiveIteratorIterator($demo);
var_dump($it->callHasChildren());
var_dump($it->callGetChildren());

$filter = new Filter($demo);
var_dump($filter->hasChildren());

$result = $it->callHasChildren();
$result = false;
var_dump($demo->hasChildren);

?>
--EXPECT--
bool(true)
NULL
bool(true)
bool(true)
3 changes: 3 additions & 0 deletions ext/zend_test/test.c
Original file line number Diff line number Diff line change
Expand Up @@ -1104,6 +1104,9 @@ static ZEND_FUNCTION(zend_call_method)

ZEND_ASSERT((argc >= 2) && (argc <= 4));
zend_call_method(obj, ce, NULL, ZSTR_VAL(method_name), ZSTR_LEN(method_name), return_value, argc - 2, arg1, arg2);
if (Z_ISREF_P(return_value)) {
zend_unwrap_reference(return_value);
}
}

/* Instantiate a class and run the constructor via object_init_with_constructor */
Expand Down
18 changes: 18 additions & 0 deletions ext/zend_test/tests/gh25404.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
--TEST--
GH-25404 (zend_call_method() forwards by-reference returns)
--EXTENSIONS--
zend_test
--FILE--
<?php

class Demo {
public mixed $v = true;
public function &returnsRef() { return $this->v; }
}

$d = new Demo();
var_dump(zend_call_method($d, 'returnsRef'));

?>
--EXPECT--
bool(true)
Loading