Избегание строгого нарушения псевдонимов в хэш-функции

Как я могу избежать строгого нарушения правил псевдонимов, пытаясь изменить 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]; 

чем получить результат, объединив эти две части:

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

person Mykola    schedule 12.01.2016    source источник
comment
Я действительно надеюсь, что фактическая строка, для которой вы вычисляете хеш, длиннее, чем то, что вы показываете, или вы будете индексировать за пределами границ при вычислении a и b.   -  person Some programmer dude    schedule 12.01.2016
comment
@Joachim Pileborg: sha256 всегда должен возвращать 32 байта хеша.   -  person Mykola    schedule 12.01.2016
comment
См. stackoverflow.com/questions/12612488/   -  person Mark Ransom    schedule 12.01.2016
comment
Это еще не означает, что вы можете выйти за пределы входных данных, вам нужно их дополнить.   -  person Some programmer dude    schedule 12.01.2016
comment
@Joachim Pileborg: Как я могу это сделать?   -  person Mykola    schedule 12.01.2016
comment
У вас есть более серьезные проблемы, чем строгое нарушение псевдонимов. Как вы скомпилировали этот char* sha_result = sha.c_str()?   -  person Lightness Races in Orbit    schedule 15.01.2016
comment
@Lightness Races in Orbit: компилируется для меня (MSVC).   -  person Mykola    schedule 15.01.2016
comment
@Lightness Races in Orbit: Что ты имеешь в виду?   -  person Mykola    schedule 15.01.2016
comment
@Mykola: Не должно. sha.c_str() это const char*. Обратите внимание на const.   -  person Lightness Races in Orbit    schedule 15.01.2016
comment
@Lightness Races in Orbit: Спасибо!)   -  person Mykola    schedule 15.01.2016


Ответы (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() там нет - значение модифицируется "на месте".

person SergeyA    schedule 12.01.2016
comment
Указывает ли что-нибудь в стандарте C++, что он не наследует ужасные правила C99 о memcpy? - person supercat; 03.09.2016