wqshr12345 opened a new issue, #3265:
URL: https://github.com/apache/brpc/issues/3265
**Describe the bug**
我们在运行单元测试结束时(以及偶发于线上服务停止时),遇到了进程 Coredump 的问题。崩溃的堆栈指向了 bvar 内部的 CHECK 失败:
```
F0409 17:44:02.410187 1487207 variable.
cpp:197] Check failed: false
`spatcher_write_latency_percentiles' must
exist
*** Check failure stack trace: ***
```
注意到这里报错的变量名原本应该是 event_dispatcher_write_latency_percentiles ,但其开头的 8
个字节丢失,被替换成了不可读的乱码。
通过排查 brpc/src/brpc/event_dispatcher.cpp 的代码,我们找到了根本原因。全局的指标指针
g_edisp_read_lantency 和 g_edisp_write_lantency 在 StopAndJoinGlobalDispatchers()
函数中被显式 delete 了,而这个函数是通过 atexit 注册的退出清理钩子:
```
static void StopAndJoinGlobalDispatchers
() {
// ... join 所有的 epoll 线程 ...
delete g_edisp_read_lantency; //
<--- 问题出在这里
delete g_edisp_write_lantency; //
<--- 问题出在这里
}
```
尽管业务层面的 epoll 线程已经被 Join,但 bvar 框架自身存在一个后台采样线程( bvar_sampler_collector
)。这个线程是一个 Leaky Singleton,伴随进程存活,永远不会被 Join 停止。当主线程通过 atexit 析构并释放这些
LatencyRecorder 时,如果后台采样线程恰好正在并发访问它们,就会发生 Use-After-Free (UAF) 。底层内存分配器(如
tcmalloc)会立刻将释放内存块的前 8 个字节覆写为一个指向空闲链表下一个节点的指针(Free-list pointer)。这直接导致了 bvar
内部的 std::string _name 被破坏(表现为前 8 个字符变成乱码),随后在 bvar::Variable::hide() 查找 Map
时必然失败并触发 CHECK(false) 导致 Coredump。
**Versions**
1.14.1
OS:
Compiler:
brpc:
protobuf:
**Additional context/screenshots**
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]