brpc icon indicating copy to clipboard operation
brpc copied to clipboard

span.cpp中destroy()方法存在内存重复释放问题,会导致服务崩掉

Open Silocean opened this issue 4 months ago • 5 comments

Describe the bug 服务开启enable_rpcz后,上线跑一段时间就会内存暴涨然后core掉,经排查定位发现在destroy()中存在内存重复释放问题。

void Span::destroy() {
    EndAsParent();
    Span* p = _next_client;
    while (p) {
        if (p == this) {
            LOG(ERROR) << "Span next_client points to self, span_id=" << p->_span_id;
        }
        Span* p_next = p->_next_client;
        p->_info.clear();
        butil::return_object(p);
        p = p_next;
    }
    _info.clear();
    butil::return_object(this);
}

如上代码,ERROR日志是我debug时加的,经过验证在服务core掉时确实打印了该行日志。 说明span链表中有span异常指向了自身。

这个问题的根源是什么?新版本是否有解决该问题?

To Reproduce

Expected behavior

Versions OS: centos7.6 Compiler: gcc4.8.5 brpc: 0.9.0 protobuf:

Additional context/screenshots

Silocean avatar Aug 18 '25 06:08 Silocean

新版本的代码有修改,不过span的使用也是需要注意一下的。你的使用场景是怎么样的?会启动bthread,并发操作span吗?

yanglimingcn avatar Aug 18 '25 09:08 yanglimingcn

新版本的代码有修改,不过span的使用也是需要注意一下的。你的使用场景是怎么样的?会启动bthread,并发操作span吗?

服务调用时会并发请求,比如我们出现core的服务是a,服务a内部调用a->b,a->c,a->d,三次请求是并发的,未显示使用bthread,用的是brpc异步请求。 这种使用方式会有问题吗?

Silocean avatar Aug 19 '25 02:08 Silocean

新版本的代码有修改,不过span的使用也是需要注意一下的。你的使用场景是怎么样的?会启动bthread,并发操作span吗?

服务调用时会并发请求,比如我们出现core的服务是a,服务a内部调用a->b,a->c,a->d,三次请求是并发的,未显示使用bthread,用的是brpc异步请求。 这种使用方式会有问题吗?

按说异步RPC也没问题,只是b、c、d必须保证在a之前结束。

yanglimingcn avatar Aug 20 '25 07:08 yanglimingcn

新版本的代码有修改,不过span的使用也是需要注意一下的。你的使用场景是怎么样的?会启动bthread,并发操作span吗?

服务调用时会并发请求,比如我们出现core的服务是a,服务a内部调用a->b,a->c,a->d,三次请求是并发的,未显示使用bthread,用的是brpc异步请求。 这种使用方式会有问题吗?

按说异步RPC也没问题,只是b、c、d必须保证在a之前结束。

是的,b、c、d肯定是保证在a之前返回的

Silocean avatar Aug 20 '25 07:08 Silocean

按说异步RPC也没问题,只是b、c、d必须保证在a之前结束。

是的,b、c、d肯定是保证在a之前返回的

比较常见的case是,a 的回调中发起 异步rpc b c d 之后没有 join b c d, 而是调用了 run->done, 在 run -> done 中会认为所有的 sub rpc 已经完成并 destroy span, 从而导致 b c d完成之后操作 dangling pointer 可以check下代码里有没有这种case

TousakaRin avatar Aug 26 '25 02:08 TousakaRin