Skip to content

[BUG] 对端在 StreamAccept() 之后、响应发送之前断开时,Stream::SetHostSocket() 会触发 CHECK(false) 导致进程崩溃 #3245

@amoxic

Description

@amoxic

Describe the bug
在服务端处理带 stream 的 RPC 时,如果 handler 中调用了 brpc::StreamAccept(),但在 brpc 发送 RPC response 并绑定 stream 到 host socket 之前,对端连接刚好断开,那么
Socket::AddStream() 会返回失败,随后 Stream::SetHostSocket() 触发 CHECK(false),直接导致进程 abort。

相关调用链:

SendRpcResponse() -> Stream::SetHostSocket() -> Socket::AddStream() -> CHECK(false)

fatal 日志类似:

stream.cpp:648 Check failed: false <stream_id> fail to add stream to host socket

To Reproduce
一个通用场景如下:

  1. 服务端收到一个带 remote stream 的请求
  2. handler 中调用 brpc::StreamAccept(...)
  3. handler 正常返回
  4. StreamAccept() 成功之后、SendRpcResponse() 执行之前,对端关闭连接或底层 TCP reset
  5. 服务端在 Stream::SetHostSocket() 中崩溃

最小化代码形态大致如下:

void Foo(::google::protobuf::RpcController* controller,
         const Request* req,
         Response* res,
         ::google::protobuf::Closure* done) {
    brpc::ClosureGuard done_guard(done);
    auto* cntl = static_cast<brpc::Controller*>(controller);

    brpc::StreamId stream_id;
    brpc::StreamOptions opt;
    opt.handler = &handler;

    if (brpc::StreamAccept(&stream_id, *cntl, &opt) != 0) {
        cntl->SetFailed("StreamAccept failed");
        return;
    }

    res->set_ok(true);
}

这个问题更容易在网络抖动、连接被主动 reset、或者对端反复重连时触发。

Expected behavior
这类情况应该被当作一个可恢复的连接失败处理:

  • 当前 stream / 当前 RPC 失败
  • 服务端进程继续运行

而不是因为 CHECK(false) 直接崩溃整个进程。

Versions
OS: Rocky 9.6
Compiler: g++ (GCC) 12.2.1
brpc: 1.16
protobuf:

Additional context/screenshots
从源码看,Socket::AddStream() 在 socket 已 failed 时返回 -1,这更像是一个运行期边界条件,而不是必须用 CHECK(false) 处理的“不可能事件”。

想确认一下,社区是否接受把这里改为普通错误返回/失败清理,而不是直接 abort?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions