c++c++11clangsanitizer

C++ type index hashing causes undefined behaviour


Following the example on https://en.cppreference.com/w/cpp/types/type_index and compiling with -fsanitize=address,integer,undefined reveals an undefined behaviour. Code is:

struct A
{
  virtual ~A()
  {}
};

struct B : A
{
};
struct C : A
{
};

int main() {
  std::unordered_map<std::type_index, std::string> type_names;
  std::cout << "A" << std::endl;
  type_names[std::type_index(typeid(int))] = "int";
  std::cout << "B" << std::endl;

  type_names[std::type_index(typeid(double))] = "double";
  std::cout << "C" << std::endl;

  type_names[std::type_index(typeid(A))] = "A";
  std::cout << "D" << std::endl;

  type_names[std::type_index(typeid(B))] = "B";
  std::cout << "E" << std::endl;

  type_names[std::type_index(typeid(C))] = "C";
  std::cout << "F" << std::endl;

  return 0;
}

which after compiled and ran yields:

A
B
C
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/typeinfo:192:26: runtime error: unsigned integer overflow: 8244747390267580164 * 33 cannot be represented in type 'unsigned long'
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/typeinfo:192:26 in
D
E
F

As seen, clang complains about undefined behaviour user defined types. Does anybody know what a correct implementation that does not cause undefined behaviour looks like?


Solution

  • Unsigned integer overflow is not undefined behaviour, however UBSan still has an option to check for it because it is often still a bug. But not in this case. This warning is provoked by a totally innocent hash function. It is supposed to have unsigned integer overflows.

    You can silence this warning.

    You can also report a bug to libc++ maintainers. They probably should add

    __attribute__((no_sanitize("integer")))
    

    or some such to the offending functions.