Skip to content

Commit

Permalink
Fix GH-14290: Member access within null pointer in extension spl
Browse files Browse the repository at this point in the history
php_pcre_replace_impl() can fail and return NULL. We should take that
error condition into account. Because other failures return false, we
return false here as well.

At first, I also thought there was a potential memory leak in the error
check of replacement_str, but found that the error condition can never
trigger, so replace that with an assertion.

Closes GH-14292.
  • Loading branch information
nielsdos committed May 21, 2024
1 parent c69c84a commit b3a56bd
Show file tree
Hide file tree
Showing 3 changed files with 28 additions and 4 deletions.
3 changes: 3 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ PHP NEWS
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
?? ??? ????, PHP 8.2.21

- SPL:
. Fixed bug GH-14290 (Member access within null pointer in extension spl).
(nielsdos)

06 Jun 2024, PHP 8.2.20

Expand Down
13 changes: 9 additions & 4 deletions ext/spl/spl_iterators.c
Original file line number Diff line number Diff line change
Expand Up @@ -1904,12 +1904,17 @@ PHP_METHOD(RegexIterator, accept)
zval *replacement = zend_read_property(intern->std.ce, Z_OBJ_P(ZEND_THIS), "replacement", sizeof("replacement")-1, 1, &rv);
zend_string *replacement_str = zval_try_get_string(replacement);

if (UNEXPECTED(!replacement_str)) {
RETURN_THROWS();
}
/* Property type is ?string, so this should always succeed. */
ZEND_ASSERT(replacement_str != NULL);

result = php_pcre_replace_impl(intern->u.regex.pce, subject, ZSTR_VAL(subject), ZSTR_LEN(subject), replacement_str, -1, &count);

if (UNEXPECTED(!result)) {
zend_string_release(replacement_str);
zend_string_release_ex(subject, false);
RETURN_FALSE;
}

if (intern->u.regex.flags & REGIT_USE_KEY) {
zval_ptr_dtor(&intern->current.key);
ZVAL_STR(&intern->current.key, result);
Expand All @@ -1926,7 +1931,7 @@ PHP_METHOD(RegexIterator, accept)
if (intern->u.regex.flags & REGIT_INVERTED) {
RETVAL_BOOL(Z_TYPE_P(return_value) != IS_TRUE);
}
zend_string_release_ex(subject, 0);
zend_string_release_ex(subject, false);
} /* }}} */

/* {{{ Returns current regular expression */
Expand Down
16 changes: 16 additions & 0 deletions ext/spl/tests/gh14290.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
--TEST--
GH-14290 (Member access within null pointer in extension spl)
--INI--
pcre.backtrack_limit=2
pcre.jit=0
--FILE--
<?php
$h = new ArrayIterator(['test' => 'test1']);
$i = new RegexIterator($h, '/^test(.*)/', RegexIterator::REPLACE);
foreach ($i as $name => $value) {
var_dump($name, $value);
}
echo "Done\n";
?>
--EXPECT--
Done

0 comments on commit b3a56bd

Please sign in to comment.