Skip to content

Commit 5bb8fc9

Browse files
committed
Merge branch 'PHP-8.5'
* PHP-8.5: Fix leak of preserved input string with FILTER_THROW_ON_FAILURE
2 parents 7147434 + 235b9b5 commit 5bb8fc9

2 files changed

Lines changed: 39 additions & 2 deletions

File tree

ext/filter/filter.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -296,10 +296,10 @@ static void php_zval_filter(zval *value, zend_long filter, zend_long flags, zval
296296
filter_func.name,
297297
ZSTR_VAL(copy_for_throwing)
298298
);
299-
zend_string_delref(copy_for_throwing);
299+
zend_string_release(copy_for_throwing);
300300
return;
301301
}
302-
zend_string_delref(copy_for_throwing);
302+
zend_string_release(copy_for_throwing);
303303
copy_for_throwing = NULL;
304304
}
305305

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
--TEST--
2+
filter: FILTER_THROW_ON_FAILURE does not leak the preserved input string
3+
--EXTENSIONS--
4+
filter
5+
--FILE--
6+
<?php
7+
// php_zval_filter() copies the input string so it can be quoted in the
8+
// exception message. A non-string scalar input (here a float / a large int)
9+
// is turned into a fresh heap string by convert_to_string(), so the copy is
10+
// the sole extra owner. Releasing it with zend_string_delref() decremented
11+
// without freeing, leaking one string per call on both the failure and the
12+
// success path. Loop and assert memory stays flat.
13+
function leakcheck(callable $fn): bool {
14+
$fn();
15+
$before = memory_get_usage();
16+
for ($i = 0; $i < 2000; $i++) {
17+
$fn();
18+
}
19+
return memory_get_usage() - $before === 0;
20+
}
21+
22+
// Validation fails -> exception thrown.
23+
var_dump(leakcheck(function () {
24+
try {
25+
filter_var(1.5, FILTER_VALIDATE_INT, ['flags' => FILTER_THROW_ON_FAILURE]);
26+
} catch (\Filter\FilterFailedException $e) {
27+
}
28+
}));
29+
30+
// Validation succeeds.
31+
var_dump(leakcheck(function () {
32+
filter_var(15, FILTER_VALIDATE_INT, ['flags' => FILTER_THROW_ON_FAILURE]);
33+
}));
34+
?>
35+
--EXPECT--
36+
bool(true)
37+
bool(true)

0 commit comments

Comments
 (0)