Skip to content

Commit 1915f08

Browse files
committed
fix: fix leak of in_thread, fix read-after-free, fix race condition UB after cluster shutdown
1 parent ec55d78 commit 1915f08

File tree

2 files changed

+24
-10
lines changed

2 files changed

+24
-10
lines changed

include/dpp/queues.h

+9-3
Original file line numberDiff line numberDiff line change
@@ -401,7 +401,7 @@ class DPP_EXPORT in_thread {
401401
/**
402402
* @brief True if ending.
403403
*/
404-
bool terminating;
404+
std::atomic<bool> terminating;
405405

406406
/**
407407
* @brief Request queue that owns this in_thread.
@@ -459,6 +459,12 @@ class DPP_EXPORT in_thread {
459459
*/
460460
~in_thread();
461461

462+
/**
463+
* @brief Terminates the thread
464+
* This will end the thread that is owned by this object, but will not join it.
465+
*/
466+
void terminate();
467+
462468
/**
463469
* @brief Post a http_request to this thread.
464470
*
@@ -545,7 +551,7 @@ class DPP_EXPORT request_queue {
545551
* 2) Requests for different endpoints go into different buckets, so that they may be requested in parallel
546552
* A global ratelimit event pauses all threads in the pool. These are few and far between.
547553
*/
548-
std::vector<in_thread*> requests_in;
554+
std::vector<std::unique_ptr<in_thread>> requests_in;
549555

550556
/**
551557
* @brief A request queued for deletion in the queue.
@@ -584,7 +590,7 @@ class DPP_EXPORT request_queue {
584590
/**
585591
* @brief Set to true if the threads should terminate
586592
*/
587-
bool terminating;
593+
std::atomic<bool> terminating;
588594

589595
/**
590596
* @brief True if globally rate limited - makes the entire request thread wait

src/dpp/queues.cpp

+15-7
Original file line numberDiff line numberDiff line change
@@ -198,15 +198,15 @@ http_request_completion_t http_request::run(cluster* owner) {
198198
request_queue::request_queue(class cluster* owner, uint32_t request_threads) : creator(owner), terminating(false), globally_ratelimited(false), globally_limited_for(0), in_thread_pool_size(request_threads)
199199
{
200200
for (uint32_t in_alloc = 0; in_alloc < in_thread_pool_size; ++in_alloc) {
201-
requests_in.push_back(new in_thread(owner, this, in_alloc));
201+
requests_in.push_back(std::make_unique<in_thread>(owner, this, in_alloc));
202202
}
203203
out_thread = new std::thread(&request_queue::out_loop, this);
204204
}
205205

206206
request_queue& request_queue::add_request_threads(uint32_t request_threads)
207207
{
208208
for (uint32_t in_alloc_ex = 0; in_alloc_ex < request_threads; ++in_alloc_ex) {
209-
requests_in.push_back(new in_thread(creator, this, in_alloc_ex + in_thread_pool_size));
209+
requests_in.push_back(std::make_unique<in_thread>(creator, this, in_alloc_ex + in_thread_pool_size));
210210
}
211211
in_thread_pool_size += request_threads;
212212
return *this;
@@ -224,16 +224,24 @@ in_thread::in_thread(class cluster* owner, class request_queue* req_q, uint32_t
224224

225225
in_thread::~in_thread()
226226
{
227-
terminating = true;
228-
in_ready.notify_one();
227+
terminate();
229228
in_thr->join();
230229
delete in_thr;
231230
}
232231

232+
void in_thread::terminate()
233+
{
234+
terminating.store(true, std::memory_order_relaxed);
235+
in_ready.notify_one();
236+
}
237+
233238
request_queue::~request_queue()
234239
{
235-
terminating = true;
240+
terminating.store(true, std::memory_order_relaxed);
236241
out_ready.notify_one();
242+
for (auto& in_thr : requests_in) {
243+
in_thr->terminate(); // signal all of them here, otherwise they will all join 1 by 1 and it will take forever
244+
}
237245
out_thread->join();
238246
delete out_thread;
239247
}
@@ -281,7 +289,7 @@ struct compare_request {
281289
void in_thread::in_loop(uint32_t index)
282290
{
283291
utility::set_thread_name(std::string("http_req/") + std::to_string(index));
284-
while (!terminating) {
292+
while (!terminating.load(std::memory_order_relaxed)) {
285293
std::mutex mtx;
286294
std::unique_lock<std::mutex> lock{ mtx };
287295
in_ready.wait_for(lock, std::chrono::seconds(1));
@@ -394,7 +402,7 @@ bool request_queue::queued_deleting_request::operator<(time_t time) const noexce
394402
void request_queue::out_loop()
395403
{
396404
utility::set_thread_name("req_callback");
397-
while (!terminating) {
405+
while (!terminating.load(std::memory_order_relaxed)) {
398406

399407
std::mutex mtx;
400408
std::unique_lock lock{ mtx };

0 commit comments

Comments
 (0)