C++ 类型索引散列导致未定义的行为

Posted

技术标签:

【中文标题】C++ 类型索引散列导致未定义的行为【英文标题】:C++ type index hashing causes undefined behaviour 【发布时间】:2021-01-26 11:50:50 【问题描述】:

按照https://en.cppreference.com/w/cpp/types/type_index 上的示例并使用-fsanitize=address,integer,undefined 进行编译会发现未定义的行为。代码是:

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;

编译并运行后产生:

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

正如所见,clang 抱怨用户定义类型的未定义行为。有人知道不会导致未定义行为的正确实现是什么样的吗?

【问题讨论】:

【参考方案1】:

无符号整数溢出不是未定义的行为,但是 UBSan 仍然可以选择检查它,因为它通常仍然是一个错误。但在这种情况下不是。这个警告是由一个完全无辜的哈希函数引起的。它应该有无符号整数溢出。

你可以silence这个警告。

您还可以向 libc++ 维护人员报告错误。他们可能应该添加

__attribute__((no_sanitize("integer")))

或一些类似的违规功能。

【讨论】:

谢谢!在查看了源代码后,我认为它很可能是无害的,因为它是一个用于查找的哈希,但对于将警告写入 stand library 感到有点惊讶。 您是否知道是否有办法忽略整个标准库? IE。非路径特定,因此它适用于多个系统。 没关系。在这里找到一个例子 https://github.com/RobotLocomotion/drake/blob/master/tools/dynamic_analysis/ubsan.supp

以上是关于C++ 类型索引散列导致未定义的行为的主要内容,如果未能解决你的问题,请参考以下文章

增量算子在字符类型边界上的行为

在哪些情况下 std::optional operator == 会导致未定义的行为?

成员函数指针值上的 Consexpr - 未定义的行为?

未定义值作为散列引用的缺失错误

超出数组最大索引的未定义行为

为啥在 C++ 中第二次调用析构函数未定义的行为?