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

Fix GH-11242: Use dynamic buffer for large length in stream mem copy

This commit is contained in:
Jakub Zelenka
2023-07-07 15:33:00 +01:00
parent c6b9db2131
commit 4a5d13e205
3 changed files with 50 additions and 9 deletions

4
NEWS
View File

@@ -22,6 +22,10 @@ PHP NEWS
. Fixed GH-11573 (RecursiveDirectoryIterator::hasChildren is slow). . Fixed GH-11573 (RecursiveDirectoryIterator::hasChildren is slow).
(nielsdos) (nielsdos)
- Streams:
. Implemented GH-11242 (_php_stream_copy_to_mem: Allow specifying a maximum
length without allocating a buffer of that size). (Jakub Zelenka)
06 Jul 2023, PHP 8.3.0alpha3 06 Jul 2023, PHP 8.3.0alpha3
- Core: - Core:

View File

@@ -0,0 +1,27 @@
--TEST--
Test file_get_contents() function with large length parameter
--INI--
memory_limit=128M
--FILE--
<?php
$file_path = __DIR__ . '/file_get_contents_with_large_length_content.txt';
$file_content = str_repeat('a', 50000);
file_put_contents($file_path, $file_content);
// test lenght limiting
$result = file_get_contents($file_path, length: 500000000);
var_dump($result === $file_content);
// test lenght limiting
$result = file_get_contents($file_path, length: 40000);
var_dump($result === str_repeat('a', 40000));
?>
--CLEAN--
<?php
unlink(__DIR__ . '/file_get_contents_with_large_length_content.txt');
?>
--EXPECT--
bool(true)
bool(true)

View File

@@ -1489,7 +1489,7 @@ PHPAPI zend_string *_php_stream_copy_to_mem(php_stream *src, size_t maxlen, int
{ {
ssize_t ret = 0; ssize_t ret = 0;
char *ptr; char *ptr;
size_t len = 0, max_len; size_t len = 0, buflen;
int step = CHUNK_SIZE; int step = CHUNK_SIZE;
int min_room = CHUNK_SIZE / 4; int min_room = CHUNK_SIZE / 4;
php_stream_statbuf ssbuf; php_stream_statbuf ssbuf;
@@ -1503,7 +1503,7 @@ PHPAPI zend_string *_php_stream_copy_to_mem(php_stream *src, size_t maxlen, int
maxlen = 0; maxlen = 0;
} }
if (maxlen > 0) { if (maxlen > 0 && maxlen < 4 * CHUNK_SIZE) {
result = zend_string_alloc(maxlen, persistent); result = zend_string_alloc(maxlen, persistent);
ptr = ZSTR_VAL(result); ptr = ZSTR_VAL(result);
while ((len < maxlen) && !php_stream_eof(src)) { while ((len < maxlen) && !php_stream_eof(src)) {
@@ -1537,20 +1537,30 @@ PHPAPI zend_string *_php_stream_copy_to_mem(php_stream *src, size_t maxlen, int
* by a downsize of the buffer, overestimate by the step size (which is * by a downsize of the buffer, overestimate by the step size (which is
* 8K). */ * 8K). */
if (php_stream_stat(src, &ssbuf) == 0 && ssbuf.sb.st_size > 0) { if (php_stream_stat(src, &ssbuf) == 0 && ssbuf.sb.st_size > 0) {
max_len = MAX(ssbuf.sb.st_size - src->position, 0) + step; buflen = MAX(ssbuf.sb.st_size - src->position, 0) + step;
if (maxlen > 0 && buflen > maxlen) {
buflen = maxlen;
}
} else { } else {
max_len = step; buflen = step;
} }
result = zend_string_alloc(max_len, persistent); result = zend_string_alloc(buflen, persistent);
ptr = ZSTR_VAL(result); ptr = ZSTR_VAL(result);
// TODO: Propagate error? // TODO: Propagate error?
while ((ret = php_stream_read(src, ptr, max_len - len)) > 0){ while ((ret = php_stream_read(src, ptr, buflen - len)) > 0) {
len += ret; len += ret;
if (len + min_room >= max_len) { if (len + min_room >= buflen) {
result = zend_string_extend(result, max_len + step, persistent); if (maxlen == len) {
max_len += step; break;
}
if (maxlen > 0 && buflen + step > maxlen) {
buflen = maxlen;
} else {
buflen += step;
}
result = zend_string_extend(result, buflen, persistent);
ptr = ZSTR_VAL(result) + len; ptr = ZSTR_VAL(result) + len;
} else { } else {
ptr += ret; ptr += ret;