Я не могу объяснить поведение выполнения этой программы:
#include <string>
#include <cstdlib>
#include <stdio.h>
typedef char u8;
typedef unsigned short u16;
size_t f(u8 *keyc, size_t len)
{
u16 *key2 = (u16 *) (keyc + 1);
size_t hash = len;
len = len / 2;
for (size_t i = 0; i < len; ++i)
hash += key2[i];
return hash;
}
int main()
{
srand(time(NULL));
size_t len;
scanf("%lu", &len);
u8 x[len];
for (size_t i = 0; i < len; i++)
x[i] = rand();
printf("out %lu\n", f(x, len));
}
Итак, когда он скомпилирован с -O3 с gcc и запускается с аргументом 25, он вызывает segfault. Без оптимизации он отлично работает. Я разобрал его: он векторизован, и компилятор предполагает, что массив key2
выровнен по 16 байт, поэтому он использует movdqa
. Очевидно, это UB, хотя я не могу это объяснить. Я знаю о правиле строжайшего aliasing, и это не тот случай (я надеюсь), потому что, насколько мне известно, строгое правило псевдонимов не работает с char
s. Почему gcc предполагает, что этот указатель выровнен? Clang отлично работает, даже с оптимизацией.
ИЗМЕНИТЬ
Я изменил unsigned char
на char
и удалил const
, он все равно segfaults.
EDIT2
Я знаю, что этот код не очень хорош, но он должен работать нормально, насколько я знаю о правиле строжайшего aliasing. Где именно нарушение?