Fix data race in freeing control block

This commit is contained in:
2025-09-11 11:32:59 -04:00
parent 0f179eed88
commit 994e31032f
2 changed files with 73 additions and 12 deletions

View File

@@ -172,19 +172,24 @@ private:
*/
void release() noexcept {
if (control_block) {
// Prevent weak count from going to 0 concurrently
control_block->increment_weak();
uint32_t prev_strong = control_block->decrement_strong();
// If this was the last strong reference, destroy the object
if (prev_strong == 1) {
T *obj = get();
obj->~T();
}
// Check if there are any weak references
uint32_t current_weak =
control_block->weak_count.load(std::memory_order_acquire);
if (current_weak == 0) {
std::free(control_block);
}
// Now release our temporary weak reference
uint32_t prev_weak = control_block->decrement_weak();
// If this was the last weak reference and we destroyed the object,
// we can free the control block
if (prev_weak == 1 && prev_strong == 1) {
std::free(control_block);
}
}
}
@@ -314,16 +319,14 @@ private:
*/
void release() noexcept {
if (control_block) {
// Prevent strong count from going to 0 concurrently
auto strong = lock();
uint32_t prev_weak = control_block->decrement_weak();
// If this was the last weak reference, check if we need to free control
// block
if (prev_weak == 1) {
uint32_t current_strong =
control_block->strong_count.load(std::memory_order_acquire);
if (current_strong == 0) {
std::free(control_block);
}
if (prev_weak == 1 && !strong) {
std::free(control_block);
}
}
}