1
0
mirror of https://github.com/php/php-src.git synced 2026-03-24 00:02:20 +01:00

ext/pcre: fix memory leaks on error paths

Fix pcre2_code leak when pcre2_pattern_info() fails after a successful
pcre2_compile(), and fix match_sets/match_data/marks leak when
offsets[1] < offsets[0] in php_pcre_match_impl().

close GH-21298
This commit is contained in:
David Carlier
2026-02-25 20:34:00 +00:00
parent f073425426
commit 78702fa470
4 changed files with 37 additions and 1 deletions

3
NEWS
View File

@@ -60,6 +60,9 @@ PHP NEWS
- PCRE: - PCRE:
. Fixed preg_match memory leak with invalid regexes. (David Carlier) . Fixed preg_match memory leak with invalid regexes. (David Carlier)
. Fixed pcre2_code leak when pcre2_pattern_info() fails after a
successful pcre2_compile(), and match_sets/match_data/marks leaks
in php_pcre_match_impl(). (David Carlier)
- PDO_PGSQL: - PDO_PGSQL:
. Fixed bug GH-21055 (connection attribute status typo for GSS negotiation). . Fixed bug GH-21055 (connection attribute status typo for GSS negotiation).

View File

@@ -840,6 +840,7 @@ PHPAPI pcre_cache_entry* pcre_get_compiled_regex_cache_ex(zend_string *regex, bo
if (key != regex) { if (key != regex) {
zend_string_release_ex(key, 0); zend_string_release_ex(key, 0);
} }
pcre2_code_free(new_entry.re);
php_error_docref(NULL, E_WARNING, "Internal pcre2_pattern_info() error %d", rc); php_error_docref(NULL, E_WARNING, "Internal pcre2_pattern_info() error %d", rc);
pcre_handle_exec_error(PCRE2_ERROR_INTERNAL); pcre_handle_exec_error(PCRE2_ERROR_INTERNAL);
return NULL; return NULL;
@@ -850,6 +851,7 @@ PHPAPI pcre_cache_entry* pcre_get_compiled_regex_cache_ex(zend_string *regex, bo
if (key != regex) { if (key != regex) {
zend_string_release_ex(key, 0); zend_string_release_ex(key, 0);
} }
pcre2_code_free(new_entry.re);
php_error_docref(NULL, E_WARNING, "Internal pcre_pattern_info() error %d", rc); php_error_docref(NULL, E_WARNING, "Internal pcre_pattern_info() error %d", rc);
pcre_handle_exec_error(PCRE2_ERROR_INTERNAL); pcre_handle_exec_error(PCRE2_ERROR_INTERNAL);
return NULL; return NULL;
@@ -1294,7 +1296,18 @@ matched:
if (subpats != NULL) { if (subpats != NULL) {
/* Try to get the list of substrings and display a warning if failed. */ /* Try to get the list of substrings and display a warning if failed. */
if (UNEXPECTED(offsets[1] < offsets[0])) { if (UNEXPECTED(offsets[1] < offsets[0])) {
if (match_sets) efree(match_sets); if (match_sets) {
for (i = 0; i < num_subpats; i++) {
zend_array_destroy(match_sets[i]);
}
efree(match_sets);
}
if (marks) {
zend_array_destroy(marks);
}
if (match_data != mdata) {
pcre2_match_data_free(match_data);
}
php_error_docref(NULL, E_WARNING, "Get subpatterns list failed"); php_error_docref(NULL, E_WARNING, "Get subpatterns list failed");
RETURN_FALSE; RETURN_FALSE;
} }

View File

@@ -0,0 +1,10 @@
--TEST--
preg_match_all() resource cleanup when \K in lookahead causes negative-length match
--FILE--
<?php
$result = preg_match_all('/(?=ab\K)a/', 'ab', $matches);
var_dump($result);
?>
--EXPECTF--
Warning: preg_match_all(): Get subpatterns list failed in %s on line %d
bool(false)

View File

@@ -0,0 +1,10 @@
--TEST--
preg_match() resource cleanup when \K in lookahead causes negative-length match
--FILE--
<?php
$result = preg_match('/(?=ab\K)a/', 'ab', $matches);
var_dump($result);
?>
--EXPECTF--
Warning: preg_match(): Get subpatterns list failed in %s on line %d
bool(false)