-
Notifications
You must be signed in to change notification settings - Fork 4.1k
Fix abort when binding response streams to a failed socket #3250
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
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
|
|
@@ -360,7 +360,19 @@ void SendRpcResponse(int64_t correlation_id, Controller* cntl, | |||||||
| Stream* s = (Stream *) stream_ptr->conn(); | ||||||||
| StreamSettings *stream_settings = meta.mutable_stream_settings(); | ||||||||
| s->FillSettings(stream_settings); | ||||||||
| s->SetHostSocket(sock); | ||||||||
| if (s->SetHostSocket(sock) != 0) { | ||||||||
| const int errcode = errno; | ||||||||
| LOG_IF(WARNING, errcode != EPIPE) | ||||||||
| << "Fail to bind response stream=" << response_stream_id | ||||||||
| << " to " << sock->description() << ": " | ||||||||
| << berror(errcode); | ||||||||
| cntl->SetFailed(errcode, "Fail to bind response stream to %s", | ||||||||
| sock->description().c_str()); | ||||||||
| Stream::SetFailed(response_stream_ids, errcode, | ||||||||
| "Fail to bind response stream to %s", | ||||||||
| sock->description().c_str()); | ||||||||
|
Comment on lines
+372
to
+373
|
||||||||
| "Fail to bind response stream to %s", | |
| sock->description().c_str()); | |
| "Fail to bind response stream to host socket"); |
Copilot
AI
Mar 25, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same varargs-forwarding issue applies here: the formatted Stream::SetFailed(remaining_stream_ids, ..., "...%s", ...) relies on undefined behavior in Stream::SetFailed/Close when the format string contains specifiers. Please address the varargs forwarding (or pre-format the message before calling Stream::SetFailed).
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -19,6 +19,7 @@ | |
| #include "brpc/stream.h" | ||
|
|
||
| #include <gflags/gflags.h> | ||
| #include "butil/string_printf.h" | ||
| #include "butil/time.h" | ||
| #include "butil/object_pool.h" | ||
| #include "butil/unique_ptr.h" | ||
|
|
@@ -56,6 +57,7 @@ Stream::Stream() | |
| , _pending_buf(NULL) | ||
| , _start_idle_timer_us(0) | ||
| , _idle_timer(0) | ||
| , _set_host_socket_ec(0) | ||
| { | ||
| _connect_meta.on_connect = NULL; | ||
| CHECK_EQ(0, bthread_mutex_init(&_connect_mutex, NULL)); | ||
|
|
@@ -643,13 +645,16 @@ int Stream::SetHostSocket(Socket *host_socket) { | |
| std::call_once(_set_host_socket_flag, [this, host_socket]() { | ||
| SocketUniquePtr ptr; | ||
| host_socket->ReAddress(&ptr); | ||
| // TODO add *this to host socke | ||
| if (ptr->AddStream(id()) != 0) { | ||
| CHECK(false) << id() << " fail to add stream to host socket"; | ||
| _set_host_socket_ec = errno ? errno : ptr->non_zero_error_code(); | ||
| return; | ||
| } | ||
| _host_socket = ptr.release(); | ||
| }); | ||
| if (_host_socket == NULL) { | ||
| errno = _set_host_socket_ec ? _set_host_socket_ec : EFAILEDSOCKET; | ||
| return -1; | ||
|
Comment on lines
+654
to
+656
|
||
| } | ||
| return 0; | ||
| } | ||
|
|
||
|
|
@@ -709,27 +714,35 @@ void Stream::Close(int error_code, const char* reason_fmt, ...) { | |
| return TriggerOnConnectIfNeed(); | ||
| } | ||
|
|
||
| int Stream::SetFailed(StreamId id, int error_code, const char* reason_fmt, ...) { | ||
| int Stream::SetFailedWithReason(StreamId id, int error_code, | ||
| const std::string& reason) { | ||
| SocketUniquePtr ptr; | ||
| if (Socket::AddressFailedAsWell(id, &ptr) == -1) { | ||
| // Don't care recycled stream | ||
| return 0; | ||
| } | ||
| Stream* s = (Stream*)ptr->conn(); | ||
| s->Close(error_code, "%s", reason.c_str()); | ||
| return 0; | ||
| } | ||
|
|
||
| int Stream::SetFailed(StreamId id, int error_code, const char* reason_fmt, ...) { | ||
| va_list ap; | ||
| va_start(ap, reason_fmt); | ||
| s->Close(error_code, reason_fmt, ap); | ||
| std::string reason; | ||
| butil::string_vprintf(&reason, reason_fmt, ap); | ||
| va_end(ap); | ||
| return 0; | ||
| return SetFailedWithReason(id, error_code, reason); | ||
| } | ||
|
|
||
| int Stream::SetFailed(const StreamIds& ids, int error_code, const char* reason_fmt, ...) { | ||
| va_list ap; | ||
| va_start(ap, reason_fmt); | ||
| for(size_t i = 0; i< ids.size(); ++i) { | ||
| Stream::SetFailed(ids[i], error_code, reason_fmt, ap); | ||
| } | ||
| std::string reason; | ||
| butil::string_vprintf(&reason, reason_fmt, ap); | ||
| va_end(ap); | ||
| for (size_t i = 0; i < ids.size(); ++i) { | ||
| Stream::SetFailedWithReason(ids[i], error_code, reason); | ||
| } | ||
| return 0; | ||
| } | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On
SetHostSocket()failure you’re logging/propagatingsock->non_zero_error_code(), butSetHostSocket()already setserrnoto the specific bind failure. Usingerrnofrom the failing call will be more accurate and avoids relying on the socket’s racy_error_codepublication timing (see comment inSocket::non_zero_error_code()).