boostorg / boostorg/lockfree

Data race in lockfree::stack

Open
#22 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
C++
Stars
160
Forks
99
PR merge metrics
No merged PRs in 30d

Description

Running my program (uses boost 1.60) through Thread Sanitizer reports the following data race:

> WARNING: ThreadSanitizer: data race (pid=23760)
> Write of size 2 at 0x7dc400000110 by thread T6:
> #0 boost::lockfree::stack, boost::parameter::void_, boost::parameter::void_>::link_nodes_atomic(boost::lockfree::stack, boost::parameter::void_, boost::parameter::void_>::node_, boost::lockfree::stack, boost::parameter::void_, boost::parameter::void_>::node_) /.../include/boost/lockfree/stack.hpp:226 (bin+0x00000079812c)
> #1 bool boost::lockfree::stack, boost::parameter::void_, boost::parameter::void_>::do_push(MYDATA\* const&) /.../include/boost/lockfree/stack.hpp:314 (bin+0x000000798034)
> #2 boost::lockfree::stack, boost::parameter::void_, boost::parameter::void_>::bounded_push(MYDATA\* const&) /.../include/boost/lockfree/stack.hpp:302 (bin+0x000000797a20)
>
> Previous read of size 2 at 0x7dc400000110 by thread T5:
> #0 boost::lockfree::detail::tagged_index::get_index() const /.../include/boost/lockfree/detail/freelist.hpp:281 (bin+0x000000797e59)
> #1 boost::lockfree::detail::fixed_size_freelist, boost::parameter::void_, boost::parameter::void_>::node, boost::lockfree::detail::compiletime_sized_freelist_storage, boost::parameter::void_, boost::parameter::void_>::node, 4096ul> >::allocate_impl() /.../include/boost/lockfree/detail/freelist.hpp:545 (bin+0x0000007982e0)
> #2 unsigned short boost::lockfree::detail::fixed_size_freelist, boost::parameter::void_, boost::parameter::void_>::node, boost::lockfree::detail::compiletime_sized_freelist_storage, boost::parameter::void_, boost::parameter::void_>::node, 4096ul> >::allocate() /.../include/boost/lockfree/detail/freelist.hpp:527 (bin+0x0000007981f9)
> #3 boost::lockfree::stack, boost::parameter::void_, boost::parameter::void_>::node\* boost::lockfree::detail::fixed_size_freelist, boost::parameter::void_, boost::parameter::void_>::node, boost::lockfree::detail::compiletime_sized_freelist_storage, boost::parameter::void_, boost::parameter::void_>::node, 4096ul> >::construct(MYDATA\* const&) /.../include/boost/lockfree/detail/freelist.hpp:443 (bin+0x000000798071)
> #4 bool boost::lockfree::stack, boost::parameter::void_, boost::parameter::void_>::do_push(MYDATA\* const&) /.../include/boost/lockfree/stack.hpp:310 (bin+0x000000798021)
> #5 boost::lockfree::stack, boost::parameter::void_, boost::parameter::void_>::bounded_push(MYDATA\* const&) /.../include/boost/lockfree/stack.hpp:302 (bin+0x000000797a20)

And another similar one:

> WARNING: ThreadSanitizer: data race (pid=23760)
> Write of size 2 at 0x7dc400001190 by thread T5:
> #0 boost::lockfree::detail::tagged_index::set_index(unsigned short) /.../include/boost/lockfree/detail/freelist.hpp:286 (bin+0x000000797cdd)
> #1 boost::lockfree::detail::fixed_size_freelist, boost::parameter::void_, boost::parameter::void_>::node, boost::lockfree::detail::compiletime_sized_freelist_storage, boost::parameter::void_, boost::parameter::void_>::node, 4096ul> >::deallocate_impl(unsigned short) /.../include/boost/lockfree/detail/freelist.hpp:585 (bin+0x000000805953)
> #2 void boost::lockfree::detail::fixed_size_freelist, boost::parameter::void_, boost::parameter::void_>::node, boost::lockfree::detail::compiletime_sized_freelist_storage, boost::parameter::void_, boost::parameter::void_>::node, 4096ul> >::deallocate(unsigned short) /.../include/boost/lockfree/detail/freelist.hpp:573 (bin+0x0000008058d0)
> #3 void boost::lockfree::detail::fixed_size_freelist, boost::parameter::void_, boost::parameter::void_>::node, boost::lockfree::detail::compiletime_sized_freelist_storage, boost::parameter::void_, boost::parameter::void_>::node, 4096ul> >::destruct(boost::lockfree::detail::tagged_index) /.../include/boost/lockfree/detail/freelist.hpp:471 (bin+0x00000080589f)
> #4 bool boost::lockfree::stack, boost::parameter::void_, boost::parameter::void_>::consume_oneboost::lockfree::detail::consume_via_copy(boost::lockfree::detail::consume_via_copy&) /.../include/boost/lockfree/stack.hpp:502 (bin+0x00000080580c)
> #5 bool boost::lockfree::stack, boost::parameter::void_, boost::parameter::void_>::pop(MYDATA_&) /.../include/boost/lockfree/stack.hpp:435 (bin+0x0000008056e2)
> #6 boost::lockfree::stack, boost::parameter::void_, boost::parameter::void_>::pop(MYDATA*&) /.../include/boost/lockfree/stack.hpp:417 (bin+0x0000008056a0)
>
> Previous read of size 2 at 0x7dc400001190 by thread T6:
> #0 bool boost::lockfree::stack, boost::parameter::void_, boost::parameter::void_>::consume_oneboost::lockfree::detail::consume_via_copy(boost::lockfree::detail::consume_via_copy&) /.../include/boost/lockfree/stack.hpp:498 (bin+0x000000805797)
> #1 bool boost::lockfree::stack, boost::parameter::void_, boost::parameter::void_>::pop(MYDATA_&) /.../include/boost/lockfree/stack.hpp:435 (bin+0x0000008056e2)
> #2 boost::lockfree::stack, boost::parameter::void_, boost::parameter::void_>::pop(MYDATA*&) /.../include/boost/lockfree/stack.hpp:417 (bin+0x0000008056a0)

Upon closer examine the offending line, I can see there is a compare_exchange_weak check immediately following it which throws away the result if the target is modified by other threads. However, the unprotected nonatomic r/w technically is still a data race in C++ language, which causes the behaviour of the program become undefined.

Contributor guide

No contributing guide indexed for this repository

Research direction

Start in boost/lockfree/stack.hpp at link_nodes_atomic, do_push, pop, and consume_one, then inspect boost/lockfree/detail/freelist.hpp around tagged_index and fixed_size_freelist. Reproduce the reported concurrent push/pop workload under ThreadSanitizer and trace the non-atomic reads and writes. Done means the reported races are addressed and the workload no longer produces ThreadSanitizer warnings.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp
Domain
backend
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.