【问题标题】:Avoiding strict aliasing violation in hash function避免哈希函数中的严格混叠违规
【发布时间】:2016-01-16 02:13:55
【问题描述】:

如何避免严格的别名规则违规,尝试修改char* sha256 函数的结果。

计算哈希值:

std::string sha = sha256("some text");
const char* sha_result = sha.c_str();
unsigned long* mod_args = reinterpret_cast<unsigned long*>(sha_result);

比获得 2 块 64 位:

unsigned long a = mod_args[1] ^ mod_args[3] ^ mod_args[5] ^ mod_args[7];
unsigned long b = mod_args[0] ^ mod_args[2] ^ mod_args[4] ^ mod_args[6]; 

比通过 concat 得到结果:

unsigned long long result = (((unsigned long long)a) << 32) | b;

【问题讨论】:

  • 我真的希望您计算哈希的实际字符串比您显示的要长,否则在计算 ab 时,您的索引将超出范围。
  • @Joachim Pileborg:sha256 必须始终返回 32 字节的哈希值。
  • 这仍然不意味着你可以超出输入数据的范围,你需要填充它。
  • @Joachim Pileborg:我该怎么做?

标签: c++ strict-aliasing


【解决方案1】:

虽然听起来令人沮丧,但唯一真正可移植、符合标准且高效的方法是通过memcpy()。使用reinterpret_cast 违反了严格的别名规则,使用union(通常建议)在您读取未写入的成员时触发未定义的行为。

但是,由于大多数编译器会优化掉 memcpy() 调用,这并不像听起来那么令人沮丧。

例如,下面的代码有两个memcpy()s:

char* foo() {
  char* sha = sha256("some text");
  unsigned int mod_args[8];
  memcpy(mod_args, sha, sizeof(mod_args));
  mod_args[5] = 0;
  memcpy(sha, mod_args, sizeof(mod_args));
  return sha;
}

产生以下优化装配:

foo():                                # @foo()
        pushq   %rax
        movl    $.L.str, %edi
        callq   sha256(char const*)
        movl    $0, 20(%rax)
        popq    %rdx
        retq

很容易看出,memcpy() 不存在 - 该值已“就地”修改。

【讨论】:

  • C++ 标准中是否有任何内容表明它没有继承 C99 关于 memcpy 的糟糕规则?
猜你喜欢
  • 1970-01-01
  • 2015-10-04
  • 2011-04-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-16
  • 2017-02-25
相关资源
最近更新 更多