Clang UBSan alignment error in tbb::concurrent_hash_map::hash_map_iterator constructor #1601
Open
Description
Summary
UBSan reports an error in the tbb::concurrent_hash_map::hash_map_iterator
constructor. It looks like the same error as the one reported for the hash_map_iterator::advance_to_next_bucket
UBSan failure here.
template<typename Container, typename Value>
hash_map_iterator<Container,Value>::hash_map_iterator( const Container &map, size_t index, const bucket *b, node_base *n ) :
my_map(&map),
my_index(index),
my_bucket(b),
my_node( static_cast<node*>(n) ) // <-- UB static_cast to node*, as n is 0x3. It is not an 8-byte aligned address.
{
if( b && !hash_map_base::is_valid(n) )
advance_to_next_bucket();
}
Version
TBB version 2020.3
Environment
Rocky8
Clang 14.0.3
Observed Behavior
When using tbb::concurrent_hash_map::range()
undefined behavior sanitizer generates this error:
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior /path_to_tbb/tbb/2020.3/include/tbb/concurrent_hash_map.h:442:18 in
/path_to_tbb/tbb/2020.3/include/tbb/concurrent_hash_map.h:377:27: runtime error: downcast of misaligned address 0x000000000003 for type 'tbb::interface5::internal::hash_map_iterator<tbb::interface5::concurrent_hash_map<int, int>, std::pair<const int, int>>::node' (aka 'tbb::interface5::concurrent_hash_map<int, int>::node'), which requires 8 byte alignment
0x000000000003: note: pointer points here
Expected Behavior
Undefined behavior sanitizer should not generate any errors when using tbb::concurrent_hash_map::range()
Steps To Reproduce
Paste into tbb-concurrent_hash_map-ubsan.cpp:
#include <tbb/concurrent_hash_map.h>
int
main()
{
tbb::concurrent_hash_map<int, int> map;
map.insert({0, 0});
auto r = map.range();
return 0;
}
Compile with: clang++ -g -fsanitize=undefined tbb-concurrent_hash_map-ubsan.cpp -o tbb-concurrent_hash_map-ubsan -ltbb
I fixed this locally by changing the hash_map_iterator constructor to this:
hash_map_iterator(const HashMapType& map,
size_t index,
const bucket* b,
node_base* n)
: my_map(&map), my_index(index), my_bucket(b), my_node(nullptr) {
if (b) {
if (!hash_map_base::is_valid(n))
advance_to_next_bucket();
else
my_node = static_cast<node*>(n);
}
}