Describe the bug (描述bug)
In the implementation of bthread_setspecific, if the current bthread has no KeyTable, a new KeyTable will be created. When the bthread ends, the created KeyTable will not be destroyed but returned to a KeyTablePool, which causes a memory leak. If we call bthread_getspecific before bthread_setspecific, the memory leak will not happen because bthread_getspecific may borrow a KeyTable from KeyTablePool and make bthread_setspecific reuse it.
This memory leak can be reproduced except these situations:
- using
brpc::thread_local_data() before bthread_setspecific. brpc::thread_local_data() calls bthread_getspecific which may borrow a KeyTable from KeyTablePool, after that, all bthread_setspecific will use this KeyTabe instead of creating new one.
- using LOG() before
bthread_setspecific, the reason is the same as above, the implementation of LOG() in brpc creates a LogStream which uses bthread_local, and it calls bthread_getspecific at first.
- calling
bthread_getspecific before bthread_setspecific, also the same as above.
To Reproduce (复现方法)
we can simply modify the echo_c++ in example to reproduce this behavior, the key code just like this.
brpc::ClosureGuard done_guard(done);
brpc::Controller* cntl =
static_cast<brpc::Controller*>(cntl_base);
if (bthread_setspecific(key1, static_cast<void*>(100)) != 0) {
//
}
and we can add log in bthread_setspecific to see if a KeyTable created or not, the result is yes.
Expected behavior (期望行为)
users can just call bthread_setspecific, instead of calling bthread_getspecific at first.
Versions (各种版本)
OS: Ubuntu 18.04.5 LTS
Compiler: g++ (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0
brpc: master branch, commit id: 0650582
protobuf: 3.0.0-9.1ubuntu1
Additional context/screenshots (更多上下文/截图)
The bthread_setspecific will create a new KeyTable and not borrow one from KeyTablePool

The KeyTable will return to KeyTablePool when bthread ends.

The bthread_getspecific may borrow a KeyTable from KeyTablePool.

Describe the bug (描述bug)
In the implementation of
bthread_setspecific, if the current bthread has no KeyTable, a new KeyTable will be created. When the bthread ends, the created KeyTable will not be destroyed but returned to a KeyTablePool, which causes a memory leak. If we callbthread_getspecificbeforebthread_setspecific, the memory leak will not happen becausebthread_getspecificmay borrow a KeyTable from KeyTablePool and makebthread_setspecificreuse it.This memory leak can be reproduced except these situations:
brpc::thread_local_data()beforebthread_setspecific.brpc::thread_local_data()callsbthread_getspecificwhich may borrow a KeyTable from KeyTablePool, after that, allbthread_setspecificwill use this KeyTabe instead of creating new one.bthread_setspecific, the reason is the same as above, the implementation of LOG() in brpc creates a LogStream which usesbthread_local, and it callsbthread_getspecificat first.bthread_getspecificbeforebthread_setspecific, also the same as above.To Reproduce (复现方法)
we can simply modify the
echo_c++inexampleto reproduce this behavior, the key code just like this.and we can add log in
bthread_setspecificto see if a KeyTable created or not, the result is yes.Expected behavior (期望行为)
users can just call
bthread_setspecific, instead of callingbthread_getspecificat first.Versions (各种版本)
OS: Ubuntu 18.04.5 LTS
Compiler: g++ (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0
brpc: master branch, commit id: 0650582
protobuf: 3.0.0-9.1ubuntu1
Additional context/screenshots (更多上下文/截图)



The
bthread_setspecificwill create a new KeyTable and not borrow one from KeyTablePoolThe KeyTable will return to KeyTablePool when bthread ends.
The
bthread_getspecificmay borrow a KeyTable from KeyTablePool.