Skip to content

Clang UBSan alignment error in tbb::concurrent_hash_map::hash_map_iterator constructor #1601

Open
@stephen-yee-adsk

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);
    }
}

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions