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

Fix GH-10406: fgets on a redis socket connection fails on PHP 8.3

This is an alternative implementation for GH-10406 that resets the
has_buffered_data flag after finishing stream read so it does not impact
other ops->read use like for example php_stream_get_line.

Closes GH-11421
This commit is contained in:
Jakub Zelenka
2023-06-10 18:22:26 +01:00
parent d22d0e26dc
commit 49fbbea2ea
5 changed files with 53 additions and 11 deletions

2
NEWS
View File

@@ -15,6 +15,8 @@ PHP NEWS
- Streams:
. Implement GH-8641 (STREAM_NOTIFY_COMPLETED over HTTP never emitted).
(nielsdos, Jakub Zelenka)
. Fix bug GH-10406 (fgets on a redis socket connection fails on PHP 8.3).
(Jakub Zelenka)
08 Jun 2023, PHP 8.3.0alpha1

View File

@@ -0,0 +1,36 @@
--TEST--
GH-11418: fgets on a redis socket connection fails on PHP 8.3
--FILE--
<?php
$serverCode = <<<'CODE'
$server = stream_socket_server('tcp://127.0.0.1:64324');
phpt_notify();
$conn = stream_socket_accept($server);
fwrite($conn, "Hi Hello"); // 8 bytes
usleep(50000);
fwrite($conn, " World\n"); // 8 bytes
fclose($conn);
fclose($server);
CODE;
$clientCode = <<<'CODE'
phpt_wait();
$fp = fsockopen("tcp://127.0.0.1:64324");
echo fread($fp, 3);
echo fgets($fp);
CODE;
include sprintf("%s/../../../openssl/tests/ServerClientTestCase.inc", __DIR__);
ServerClientTestCase::getInstance()->run($clientCode, $serverCode);
?>
--EXPECT--
Hi Hello World

View File

@@ -211,6 +211,9 @@ struct _php_stream {
* PHP_STREAM_FCLOSE_XXX as appropriate */
uint8_t fclose_stdiocast:2;
/* flag to mark whether the stream has buffered data */
uint8_t has_buffered_data:1;
char mode[16]; /* "rwb" etc. ala stdio */
uint32_t flags; /* PHP_STREAM_FLAG_XXX */
@@ -227,7 +230,6 @@ struct _php_stream {
size_t readbuflen;
zend_off_t readpos;
zend_off_t writepos;
ssize_t didread;
/* how much data to read when filling buffer */
size_t chunk_size;

View File

@@ -694,8 +694,7 @@ out_is_eof:
PHPAPI ssize_t _php_stream_read(php_stream *stream, char *buf, size_t size)
{
ssize_t toread = 0;
stream->didread = 0;
ssize_t toread = 0, didread = 0;
while (size > 0) {
@@ -714,7 +713,8 @@ PHPAPI ssize_t _php_stream_read(php_stream *stream, char *buf, size_t size)
stream->readpos += toread;
size -= toread;
buf += toread;
stream->didread += toread;
didread += toread;
stream->has_buffered_data = 1;
}
/* ignore eof here; the underlying state might have changed */
@@ -727,14 +727,14 @@ PHPAPI ssize_t _php_stream_read(php_stream *stream, char *buf, size_t size)
if (toread < 0) {
/* Report an error if the read failed and we did not read any data
* before that. Otherwise return the data we did read. */
if (stream->didread == 0) {
if (didread == 0) {
return toread;
}
break;
}
} else {
if (php_stream_fill_read_buffer(stream, size) != SUCCESS) {
if (stream->didread == 0) {
if (didread == 0) {
return -1;
}
break;
@@ -751,9 +751,10 @@ PHPAPI ssize_t _php_stream_read(php_stream *stream, char *buf, size_t size)
}
}
if (toread > 0) {
stream->didread += toread;
didread += toread;
buf += toread;
size -= toread;
stream->has_buffered_data = 1;
} else {
/* EOF, or temporary end of data (for non-blocking mode). */
break;
@@ -767,11 +768,12 @@ PHPAPI ssize_t _php_stream_read(php_stream *stream, char *buf, size_t size)
}
}
if (stream->didread > 0) {
stream->position += stream->didread;
if (didread > 0) {
stream->position += didread;
stream->has_buffered_data = 0;
}
return stream->didread;
return didread;
}
/* Like php_stream_read(), but reading into a zend_string buffer. This has some similarity

View File

@@ -168,7 +168,7 @@ static ssize_t php_sockop_read(php_stream *stream, char *buf, size_t count)
/* Special handling for blocking read. */
if (sock->is_blocked) {
/* Find out if there is any data buffered from the previous read. */
bool has_buffered_data = stream->didread > 0;
bool has_buffered_data = stream->has_buffered_data;
/* No need to wait if there is any data buffered or no timeout. */
bool dont_wait = has_buffered_data ||
(sock->timeout.tv_sec == 0 && sock->timeout.tv_usec == 0);