避免哈希函数中的严格别名冲突

Myk*_*ola 0 c++ strict-aliasing

如何避免严格别名规则违规,试图修改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);
Run Code Online (Sandbox Code Playgroud)

得到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]; 
Run Code Online (Sandbox Code Playgroud)

而不是通过concat获得结果两件:

unsigned long long result = (((unsigned long long)a) << 32) | b;
Run Code Online (Sandbox Code Playgroud)

Ser*_*eyA 7

尽管听起来令人沮丧,唯一真正的便携式,符合标准且有效的方式是通过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;
}
Run Code Online (Sandbox Code Playgroud)

产生以下优化组装:

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

很容易看到,没有memcpy()- 价值被"适当地"修改.