mirror of
https://github.com/php/php-src.git
synced 2025-08-16 05:58:45 +02:00
Fix GH-17650: realloc with size 0 in user_filters.c
If the returned buffer string is of length 0, then a realloc can happen with length 0. However, the behaviour is implementation-defined. From 7.20.3.1 of C11 spec: > If the size of the space requested is zero, the behavior is > implementation-defined: either a null pointer is returned, > or the behavior is as if the size were some nonzero value, > except that the returned pointer shall not be used to access an object This is problematic for the test case on my system as it returns NULL, causing a memleak and later using it in memcpy causing UB. The bucket code is not prepared to handle a NULL pointer. To solve this, we use MAX to clamp the size to 1 at the least. Closes GH-17656.
This commit is contained in:
parent
00d4390ea1
commit
fd5d6ad5bd
3 changed files with 39 additions and 1 deletions
3
NEWS
3
NEWS
|
@ -31,6 +31,9 @@ PHP NEWS
|
||||||
. Partially fixed bug GH-17387 (Trivial crash in phpdbg lexer). (nielsdos)
|
. Partially fixed bug GH-17387 (Trivial crash in phpdbg lexer). (nielsdos)
|
||||||
. Fix memory leak in phpdbg calling registered function. (nielsdos)
|
. Fix memory leak in phpdbg calling registered function. (nielsdos)
|
||||||
|
|
||||||
|
- Streams:
|
||||||
|
. Fixed bug GH-17650 (realloc with size 0 in user_filters.c). (nielsdos)
|
||||||
|
|
||||||
13 Feb 2025, PHP 8.3.17
|
13 Feb 2025, PHP 8.3.17
|
||||||
|
|
||||||
- Core:
|
- Core:
|
||||||
|
|
35
ext/standard/tests/streams/gh17650.phpt
Normal file
35
ext/standard/tests/streams/gh17650.phpt
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
--TEST--
|
||||||
|
GH-17650 (realloc with size 0 in user_filters.c)
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
class testfilter extends php_user_filter {
|
||||||
|
function filter($in, $out, &$consumed, $closing): int {
|
||||||
|
while ($bucket = stream_bucket_make_writeable($in)) {
|
||||||
|
$bucket->data = '';
|
||||||
|
$consumed += strlen($bucket->data);
|
||||||
|
stream_bucket_append($out, $bucket);
|
||||||
|
}
|
||||||
|
return PSFS_PASS_ON;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stream_filter_register('testfilter','testfilter');
|
||||||
|
|
||||||
|
$text = "Hello There!";
|
||||||
|
|
||||||
|
$fp = fopen('php://memory', 'w+');
|
||||||
|
fwrite($fp, $text);
|
||||||
|
|
||||||
|
rewind($fp);
|
||||||
|
stream_filter_append($fp, 'testfilter', STREAM_FILTER_READ, 'testuserfilter');
|
||||||
|
|
||||||
|
while ($x = fgets($fp)) {
|
||||||
|
var_dump($x);
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose($fp);
|
||||||
|
|
||||||
|
echo "Done\n";
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
Done
|
|
@ -398,7 +398,7 @@ static void php_stream_bucket_attach(int append, INTERNAL_FUNCTION_PARAMETERS)
|
||||||
bucket = php_stream_bucket_make_writeable(bucket);
|
bucket = php_stream_bucket_make_writeable(bucket);
|
||||||
}
|
}
|
||||||
if (bucket->buflen != Z_STRLEN_P(pzdata)) {
|
if (bucket->buflen != Z_STRLEN_P(pzdata)) {
|
||||||
bucket->buf = perealloc(bucket->buf, Z_STRLEN_P(pzdata), bucket->is_persistent);
|
bucket->buf = perealloc(bucket->buf, MAX(Z_STRLEN_P(pzdata), 1), bucket->is_persistent);
|
||||||
bucket->buflen = Z_STRLEN_P(pzdata);
|
bucket->buflen = Z_STRLEN_P(pzdata);
|
||||||
}
|
}
|
||||||
memcpy(bucket->buf, Z_STRVAL_P(pzdata), bucket->buflen);
|
memcpy(bucket->buf, Z_STRVAL_P(pzdata), bucket->buflen);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue