Skip to content

Commit 9f5bd9b

Browse files
committed
Fix SIGSEGV in lock_free_queue::guard_ptr
1 parent d90b06e commit 9f5bd9b

File tree

3 files changed

+41
-28
lines changed

3 files changed

+41
-28
lines changed

include/coro/detail/lockfree_queue.hpp

+25-25
Original file line numberDiff line numberDiff line change
@@ -69,30 +69,26 @@ class guard_ptr
6969
{
7070
using namespace std::chrono_literals;
7171

72-
node<T>* current = ref.load(std::memory_order::relaxed);
7372
do
7473
{
75-
node<T>* result = current;
76-
m_node_ptr = current;
77-
if (m_node_ptr)
74+
m_node_ptr = ref.load(std::memory_order::acquire);
75+
if (!m_node_ptr)
7876
{
79-
m_node_ptr->ref_count.fetch_add(1, std::memory_order::acq_rel);
80-
if (m_node_ptr->is_removed.load(std::memory_order::acquire))
81-
{
82-
decrement();
83-
m_is_removed = true;
84-
return;
85-
}
77+
return;
8678
}
87-
current = ref.load(std::memory_order::acquire);
88-
if (result == current)
89-
break;
90-
91-
if (m_node_ptr)
79+
if (m_node_ptr->is_removed.load(std::memory_order::acquire))
9280
{
93-
decrement();
81+
m_is_removed = true;
82+
m_node_ptr = nullptr;
83+
return;
84+
}
85+
node<T>* current = ref.load(std::memory_order::acquire);
86+
if (m_node_ptr == current)
87+
{
88+
break;
9489
}
9590
} while (true);
91+
m_node_ptr->ref_count.fetch_add(1, std::memory_order::acq_rel);
9692
}
9793

9894
void remove()
@@ -222,33 +218,33 @@ class lockfree_queue
222218
using namespace std::chrono_literals;
223219

224220
auto new_node = m_alloc.allocate(value);
221+
assert(new_node->next.load() == nullptr);
225222
while (true)
226223
{
227224
guard_type tail_guard(m_tail, [this](node_type* n) { dispose_node(n); });
228225
if (tail_guard.is_removed())
229226
{
230227
continue;
231228
}
232-
auto tail_node = tail_guard.value();
233-
guard_type next_guard(tail_node->next, [this](node_type* n) { dispose_node(n); });
234-
if (next_guard.is_removed())
235-
{
236-
continue;
237-
}
238-
auto next_node = next_guard.value();
229+
auto tail_node = tail_guard.value();
230+
assert(tail_node != new_node);
231+
auto next_node = tail_node->next.load(std::memory_order::acquire);
239232

240233
if (next_node != nullptr)
241234
{
235+
assert(tail_node != next_node);
236+
242237
// Tail is misplaced, advance it
243238
m_tail.compare_exchange_weak(
244239
tail_node, next_node, std::memory_order::release, std::memory_order::relaxed);
245240
continue;
246241
}
247242

248-
node_type* expected{};
243+
node_type* expected = nullptr;
249244
if (tail_node->next.compare_exchange_strong(
250245
expected, new_node, std::memory_order::release, std::memory_order::relaxed))
251246
{
247+
assert(tail_node != new_node);
252248
m_tail.compare_exchange_strong(
253249
tail_node, new_node, std::memory_order::release, std::memory_order::relaxed);
254250
return;
@@ -291,12 +287,16 @@ class lockfree_queue
291287

292288
if (head_node == tail_node)
293289
{
290+
assert(tail_node != next_node);
291+
294292
// It is needed to help push()
295293
m_tail.compare_exchange_strong(
296294
tail_node, next_node, std::memory_order::release, std::memory_order::relaxed);
297295
continue;
298296
}
299297

298+
assert(head_node != next_node);
299+
300300
if (m_head.compare_exchange_strong(
301301
head_node, next_node, std::memory_order::acquire, std::memory_order::relaxed))
302302
{

src/condition_variable.cpp

+6-2
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,8 @@ auto detail::strategy_based_on_io_scheduler::timeout_task(
7272
using namespace std::chrono_literals;
7373

7474
assert(!m_scheduler.expired());
75-
auto deadline = steady_clock::now() + timeout;
75+
auto deadline = steady_clock::now() + timeout;
76+
auto stop_token = stop_source.get_token();
7677

7778
while ((steady_clock::now() < deadline) && !stop_source.stop_requested())
7879
{
@@ -84,7 +85,10 @@ auto detail::strategy_based_on_io_scheduler::timeout_task(
8485
}
8586
}
8687

87-
extract_waiter(wo.get());
88+
if (!stop_token.stop_requested())
89+
{
90+
extract_waiter(wo.get());
91+
}
8892
co_return timeout_status::timeout;
8993
}
9094

test/test_condition_variable.cpp

+10-1
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,7 @@ TEST_CASE("condition_variable for thread-safe-queue between producers and consum
245245
{
246246
{
247247
auto ulock = co_await bp.m.lock();
248+
REQUIRE_FALSE(bp.m.try_lock());
248249
auto value = bp.next.fetch_add(1, std::memory_order::acq_rel);
249250

250251
// limit for end of test
@@ -268,7 +269,14 @@ TEST_CASE("condition_variable for thread-safe-queue between producers and consum
268269
while (true)
269270
{
270271
auto ulock = co_await bp.m.lock();
271-
co_await bp.cv.wait(ulock, [&bp]() { return bp.q.size() || bp.cancel.load(std::memory_order::acquire); });
272+
co_await bp.cv.wait(
273+
ulock,
274+
[&bp]()
275+
{
276+
REQUIRE_FALSE(bp.m.try_lock());
277+
return bp.q.size() || bp.cancel.load(std::memory_order::acquire);
278+
});
279+
REQUIRE_FALSE(bp.m.try_lock());
272280
if (bp.cancel.load(std::memory_order::acquire))
273281
{
274282
break;
@@ -294,6 +302,7 @@ TEST_CASE("condition_variable for thread-safe-queue between producers and consum
294302
{
295303
{
296304
auto ulock = co_await bp.m.lock();
305+
REQUIRE_FALSE(bp.m.try_lock());
297306
if ((bp.next.load(std::memory_order::acquire) >= bp.max_value) && bp.q.empty())
298307
{
299308
break;

0 commit comments

Comments
 (0)