Skip to content

Commit 78702fa

Browse files
committed
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
1 parent f073425 commit 78702fa

File tree

4 files changed

+37
-1
lines changed

4 files changed

+37
-1
lines changed

NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,9 @@ PHP NEWS
6060

6161
- PCRE:
6262
. Fixed preg_match memory leak with invalid regexes. (David Carlier)
63+
. Fixed pcre2_code leak when pcre2_pattern_info() fails after a
64+
successful pcre2_compile(), and match_sets/match_data/marks leaks
65+
in php_pcre_match_impl(). (David Carlier)
6366

6467
- PDO_PGSQL:
6568
. Fixed bug GH-21055 (connection attribute status typo for GSS negotiation).

ext/pcre/php_pcre.c

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -840,6 +840,7 @@ PHPAPI pcre_cache_entry* pcre_get_compiled_regex_cache_ex(zend_string *regex, bo
840840
if (key != regex) {
841841
zend_string_release_ex(key, 0);
842842
}
843+
pcre2_code_free(new_entry.re);
843844
php_error_docref(NULL, E_WARNING, "Internal pcre2_pattern_info() error %d", rc);
844845
pcre_handle_exec_error(PCRE2_ERROR_INTERNAL);
845846
return NULL;
@@ -850,6 +851,7 @@ PHPAPI pcre_cache_entry* pcre_get_compiled_regex_cache_ex(zend_string *regex, bo
850851
if (key != regex) {
851852
zend_string_release_ex(key, 0);
852853
}
854+
pcre2_code_free(new_entry.re);
853855
php_error_docref(NULL, E_WARNING, "Internal pcre_pattern_info() error %d", rc);
854856
pcre_handle_exec_error(PCRE2_ERROR_INTERNAL);
855857
return NULL;
@@ -1294,7 +1296,18 @@ PHPAPI void php_pcre_match_impl(pcre_cache_entry *pce, zend_string *subject_str,
12941296
if (subpats != NULL) {
12951297
/* Try to get the list of substrings and display a warning if failed. */
12961298
if (UNEXPECTED(offsets[1] < offsets[0])) {
1297-
if (match_sets) efree(match_sets);
1299+
if (match_sets) {
1300+
for (i = 0; i < num_subpats; i++) {
1301+
zend_array_destroy(match_sets[i]);
1302+
}
1303+
efree(match_sets);
1304+
}
1305+
if (marks) {
1306+
zend_array_destroy(marks);
1307+
}
1308+
if (match_data != mdata) {
1309+
pcre2_match_data_free(match_data);
1310+
}
12981311
php_error_docref(NULL, E_WARNING, "Get subpatterns list failed");
12991312
RETURN_FALSE;
13001313
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
--TEST--
2+
preg_match_all() resource cleanup when \K in lookahead causes negative-length match
3+
--FILE--
4+
<?php
5+
$result = preg_match_all('/(?=ab\K)a/', 'ab', $matches);
6+
var_dump($result);
7+
?>
8+
--EXPECTF--
9+
Warning: preg_match_all(): Get subpatterns list failed in %s on line %d
10+
bool(false)
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
--TEST--
2+
preg_match() resource cleanup when \K in lookahead causes negative-length match
3+
--FILE--
4+
<?php
5+
$result = preg_match('/(?=ab\K)a/', 'ab', $matches);
6+
var_dump($result);
7+
?>
8+
--EXPECTF--
9+
Warning: preg_match(): Get subpatterns list failed in %s on line %d
10+
bool(false)

0 commit comments

Comments
 (0)