mardi 1 janvier 2019

Boost lock-free queue is triggering clang's thread sanitizer and sanitizer blacklist

I created a lock-free object pool using boost's lock-free queue, version 1.68. While it seems to be working fine, I keep getting these warnings from clang's thread sanitizer in the function pop().

WARNING: ThreadSanitizer: data race (pid=32452)
  Write of size 2 at 0x7b4400081e00 by thread T54 (mutexes: write M3349, write M3517):
    #0 boost::lockfree::detail::tagged_index::set_index(unsigned short) /opt/boost/boost/lockfree/detail/freelist.hpp:292:15 (Exchange-tests+0xb37c09)
    #1 boost::lockfree::detail::fixed_size_freelist<boost::lockfree::queue<unsigned long, boost::lockfree::fixed_sized<true> >::node, boost::lockfree::detail::runtime_sized_freelist_storage<boost::lockfree::queue<unsigned long, boost::lockfree::fixed_sized<true> >::node, std::allocator<boost::lockfree::queue<unsigned long, boost::lockfree::fixed_sized<true> >::node> > >::deallocate_impl(unsigned short) /opt/boost/boost/lockfree/detail/freelist.hpp:592:33 (Exchange-tests+0xb3c31f)
    #2 void boost::lockfree::detail::fixed_size_freelist<boost::lockfree::queue<unsigned long, boost::lockfree::fixed_sized<true> >::node, boost::lockfree::detail::runtime_sized_freelist_storage<boost::lockfree::queue<unsigned long, boost::lockfree::fixed_sized<true> >::node, std::allocator<boost::lockfree::queue<unsigned long, boost::lockfree::fixed_sized<true> >::node> > >::deallocate<true>(unsigned short) /opt/boost/boost/lockfree/detail/freelist.hpp:580:13 (Exchange-tests+0xb3c23b)
    #3 void boost::lockfree::detail::fixed_size_freelist<boost::lockfree::queue<unsigned long, boost::lockfree::fixed_sized<true> >::node, boost::lockfree::detail::runtime_sized_freelist_storage<boost::lockfree::queue<unsigned long, boost::lockfree::fixed_sized<true> >::node, std::allocator<boost::lockfree::queue<unsigned long, boost::lockfree::fixed_sized<true> >::node> > >::destruct<true>(boost::lockfree::detail::tagged_index) /opt/boost/boost/lockfree/detail/freelist.hpp:478:9 (Exchange-tests+0xb3c1d7)
    #4 bool boost::lockfree::queue<unsigned long, boost::lockfree::fixed_sized<true> >::pop<unsigned long>(unsigned long&) /opt/boost/boost/lockfree/queue.hpp:418:39 (Exchange-tests+0xb3c102)
    #5 boost::lockfree::queue<unsigned long, boost::lockfree::fixed_sized<true> >::pop(unsigned long&) /opt/boost/boost/lockfree/queue.hpp:375:16 (Exchange-tests+0xb3bda8)
    #6 ObjectPool<MarketsController>::borrowObj() 
...

  Previous atomic read of size 4 at 0x7b4400081e00 by thread T52 (mutexes: write M3339, write M3518):
    #0 __tsan_atomic32_load /tmp/final/llvm.src/projects/compiler-rt/lib/tsan/rtl/tsan_interface_atomic.cc:535:3 (Exchange-tests+0x503e11)
    #1 std::atomic<boost::lockfree::detail::tagged_index>::load(std::memory_order) const /usr/lib/gcc/x86_64-linux-gnu/7.3.0/../../../../include/c++/7.3.0/atomic:250:2 (Exchange-tests+0xb37e97)
    #2 bool boost::lockfree::queue<unsigned long, boost::lockfree::fixed_sized<true> >::pop<unsigned long>(unsigned long&) /opt/boost/boost/lockfree/queue.hpp:394:54 (Exchange-tests+0xb3beca)
    #3 boost::lockfree::queue<unsigned long, boost::lockfree::fixed_sized<true> >::pop(unsigned long&) /opt/boost/boost/lockfree/queue.hpp:375:16 (Exchange-tests+0xb3bda8)
    #4 ObjectPool<MController>::borrowObj() 
...

Following boost's code I see that this boost/lockfree/detail/freelist.hpp:292:

void set_index(index_t i)
{
    index = i; // this line
}

and this boost/lockfree/queue.hpp:394:54:

tagged_node_handle next = head_ptr->next.load(memory_order_acquire);

  1. I'm not sure how to react to this, but how worried should I be? Is this a bug in boost or the sanitizer? Or maybe something wrong I did?

  2. I almost gave up on the sanitizer's blacklist. It never works (using fun:*tagged_index*set_index* for example to disable this boost warning). I'm worried I'd be flooded with these warnings and will not see the real, meaningful ones. What's the right way to deal with this?

Aucun commentaire:

Enregistrer un commentaire