Fix #70198: Checking liveness does not work as expected#1456
Fix #70198: Checking liveness does not work as expected#1456shafreeck wants to merge 1 commit intophp:masterfrom
Conversation
Syscall recv won't set errno if the call successes. So if errno is EWOULDBLOCK and the peer closed connection, recv returns 0 and errno remains EWOULDBLOCK. That will fail the if condition. The bug may confuse the users with some unexpected behavier.
|
Except of checking EWOULDBLOCK, check EAGAIN for a portable reason. Refer |
|
Opened a bug ticket #70198 at https://bugs.php.net/ |
There was a problem hiding this comment.
This doesn't look correct at least on Windows where php_socket_errno() is a real function call.
There was a problem hiding this comment.
Can you explain more details ?
There was a problem hiding this comment.
Please see the declaration of php_socket_errno(). If you've got an errno set, next successful function call will clear it. Therefore it needs to be saved before to check multiple error codes.
Thanks.
There was a problem hiding this comment.
@staabm nope, it is the exact fix - 0 == ret means the counterpart did shutdown, no need to check errno as that means the stream is not alive anyway. errno only needs to be checked if ret < 0. However one could merge these two cases with || as both set alive = 0.
Thanks.
There was a problem hiding this comment.
@weltling || could be used but I think it makes more clearly to separate it into two if statements. I would like to merge it if the php team prefers a merging style.
There was a problem hiding this comment.
@shafreeck yep, || was just a note, doesn't matter much. But please save the php_socket_errno() result before checking it twice, as possibly the second condition will not work as expected.
Thanks.
|
@shafreeck do you have some reproduce case for this? Thanks. |
|
@weltling You can look about phpredis/phpredis#643, which is a bug in phpredis caused by this issue. I got a reproduce steps there. |
|
@shafreeck ok, i see it could be possible issue, though question -
From where come EWOULDBLOCK? It only can come from one of the previous function calls, fe php_pollfd_for() ... shouldn't that be handled in first place? With the test - i have no redis database, so it would be untestable. It were great to reconstruct the behavior with the legacy PHP functions. The functionality is a very low level so the changes should be testable. I'll be testing this manually as well, but please think about a synthetic reproduce case, maybe using exec or alike. Thanks. |
EWOULDBLOCK can come from another PHP ext or somewhere that you really do not know because errno is a global variable. The errno won't be touched if a syscall successes (at least in linux). So It is really a challenge to reproduce the issue without set errno to EWOULDBLOCK first. I am trying to make it . |
|
@weltling It is really difficult to reproduce it without set errno to EWOULDBLOCK. However, I am sure that this issue would be triggered in some special cases. Ex.
Step 3 acts as set errno to EWOULDBLOCK manually. I do not know which ext would act as step 3. I will be very appreciated if someone could supply an exist php ext acts like step 3 |
|
@shafreeck that was my commit actually, just thought it's faster than a long conversation. I've also added a test checking recv() == 0, see ext/standard/tests/streams/bug70198.phpt ... currently waiting on travis. Also extended a couple of other places with EAGAIN check to fit with POSIX man. But actually, isn't it worth to backport into 5.6? thanks. |
|
Comment on behalf of ab at php.net: @shafreeck backported the relevant part into 5.6. Thanks! |
…xt/openssl/xp_ssl.c - causing use of dead socket php_socket_errno() may return a stale value when recv returns a value >= 0. As such, the liveness check is wrong. This is the same bug as #70198 (fixed in phpGH-1456). So we fix it in the same way.
Syscall recv won't set errno if the call successes. So if errno is
EWOULDBLOCK and the peer closed connection, recv returns 0 and errno
remains EWOULDBLOCK. That will fail the if condition. The bug may
confuse the users with some unexpected behavier.