Skip to content

Commit 713f662

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().
1 parent f073425 commit 713f662

File tree

3 files changed

+34
-1
lines changed

3 files changed

+34
-1
lines changed

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)