Skip to content

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

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions ext/standard/tests/streams/gh11418.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
--TEST--
GH-10406: 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
4 changes: 3 additions & 1 deletion main/php_streams.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand All @@ -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;
Expand Down
20 changes: 11 additions & 9 deletions main/streams/streams.c
Original file line number Diff line number Diff line change
Expand Up @@ -680,8 +680,7 @@ PHPAPI zend_result _php_stream_fill_read_buffer(php_stream *stream, size_t size)

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) {

Expand All @@ -700,7 +699,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 */
Expand All @@ -713,14 +713,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;
Expand All @@ -737,9 +737,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;
Expand All @@ -753,11 +754,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
Expand Down
2 changes: 1 addition & 1 deletion main/streams/xp_socket.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down