WritableResourceStream::handleWrite() enters infinite loop on broken TLS socket (EPIPE without PHP warning)
Chưa có ai nhận issue này.
Đánh giá
- Độ khó
- 2/5
- Thời gian dự kiến
- 1-3 giờ
- Mức phù hợp với người mới
- 76/100
- Loại issue
- Lỗi
- Độ rõ ràng
- Đặc tả rõ ràng
- Mức độ hoạt động
- Ít trao đổi
- Công nghệ
- php
- Lĩnh vực
- backend, networking
Hướng nghiên cứu
Bắt đầu trong src/WritableResourceStream.php tại guard của handleWrite() quanh dòng 151, sau đó lần theo cách các kết quả của fwrite() và các cảnh báo được bắt lại ảnh hưởng đến bộ đệm ghi và listener. Tái hiện bằng một ReactPHP SecureServer và một máy khách TLS bị kết thúc đột ngột trong khi các thao tác ghi đang được xếp hàng. Được xem là hoàn tất khi một lần ghi trả về false mà không có cảnh báo sẽ đóng stream, còn lần ghi trả về zero vẫn giữ nguyên hành vi hiện có phụ thuộc vào cảnh báo và không còn gây ra vòng lặp CPU.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Mô tả
On PHP 8.x with react/socket's SecureServer (TLS), when a remote client disconnects abruptly, epoll reports EPOLLOUT|EPOLLHUP on the dead socket FD. WritableResourceStream::handleWrite() calls fwrite(), which returns false because the kernel write() returns -1 EPIPE. However, PHP's OpenSSL stream wrapper does not call php_error_docref() for SSL_ERROR_SYSCALL+EPIPE errors in all code paths. The set_error_handler capture therefore gets nothing ($error === null).
The guard evaluates to false, so close() is never called. WritableResourceStream then silently passes false to substr() (implicit cast to 0 in non-strict mode), leaving the write buffer unchanged and the write listener active. epoll keeps returning EPOLLOUT|EPOLLHUP, fwrite() keeps returning false silently - 100% CPU lockup.
Reproduction: use react/socket SecureServer with TLS, kill a client with kill -9 while the server has queued writes to that client.
Fix: separate the $sent === false case (hard error - always close) from $sent === 0 (may be transient EAGAIN/WANT_WRITE - only close when PHP warning is present):
// Before
if (($sent === 0 || $sent === false) && $error !== null) {
// After
if ($sent === false || ($sent === 0 && $error !== null)) {
This issue was investigated with the help of AI, but the 100% CPU usage issue is real and after applying the above fix on production, it seems to have disappeared.
- Ngôn ngữ chính
- PHP
- Star
- 692
- Fork
- 63
- Chỉ số merge pull request
- Không có pull request nào được merge trong 30 ngày
Hướng dẫn đóng góp
Chưa lập chỉ mục được hướng dẫn đóng góp cho kho mã nguồn này
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Issue khác của reactphp/stream
-
Roadmap to reactphp/stream v3 Đang mởmaintenance
Độ khó 5/5 Hơn một tuần Mức phù hợp với người mới 20/100
Tất cả issue của reactphp/stream
Issue tương tự
-
sync-en
Độ khó 1/5 1-3 giờ Mức phù hợp với người mới 85/100
-
sync-en
Độ khó 1/5 1-3 giờ Mức phù hợp với người mới 85/100
-
Перевод устарел
Độ khó 1/5 1-3 giờ Mức phù hợp với người mới 78/100
-
[6.x]: "Cannot use object of type stdClass as array" loading Users index (regression of #19182) Đang mở
Độ khó 1/5 Dưới một giờ Mức phù hợp với người mới 90/100
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 85/100