Russian Qt Forum
Ноябрь 22, 2024, 12:04 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: Тупой вопрос про выравнивание  (Прочитано 6785 раз)
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3260


Просмотр профиля
« : Май 27, 2019, 19:12 »

Вот есть такой код:
Код:
#define AES_N_BLOCK 16

void copy_and_key(quint8 d[AES_N_BLOCK], const quint8 s[AES_N_BLOCK], const quint8 k[AES_N_BLOCK])
{
    ((quint64*)d)[0] = ((quint64*)s)[0] ^ ((quint64*)k)[0];
    ((quint64*)d)[1] = ((quint64*)s)[1] ^ ((quint64*)k)[1];
}

Юзается так:
Код:
void aes_decrypt(const quint8 in[AES_N_BLOCK], quint8 out[AES_N_BLOCK]) {
    quint8 s1[AES_N_BLOCK], r;
    copy_and_key(s1, in, keySchedule + rnd * AES_N_BLOCK);
    // тут что-то делаем c s1
}

Анализатор кланга ругается что одна из ячеек s1 не иницилизирована.
Если я убираю reinterpret_cast из quint8 в quint64 и xor'ю в цикле, то ругаться перестает.
Это бага анализатора? Или это связано с выравниванием - что никто не гарантирует выравнивание quint8 s1[16] на 8 байт? Или гарантируют? На x86_64 добиться левого выравнивания на стеке\маллоком не удалось...

В код можно потупить тут, у нас копия, но почти 1в1, судя по всему. Функции aes_cbc_decrypt, aes_decrypt, copy_and_key
« Последнее редактирование: Май 27, 2019, 19:15 от Авварон » Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #1 : Май 28, 2019, 11:43 »

Объявите union'ом, для удобства присваивания quint64 первым
Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3260


Просмотр профиля
« Ответ #2 : Май 28, 2019, 11:52 »

Объявите union'ом, для удобства присваивания quint64 первым

Это такое же UB как и код выше. Нельзя использовать union для type prunning'а.
Единственный способ делать type prunning - это memcopy, и да, это тоже помогает "заткнуть" анализатор.
Но всё же хочется воспроизвести проблему, я что не пытаюсь сделать - адреса выровнены, хоть убей. Или это очередная "фишка" х86?
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #3 : Май 28, 2019, 12:46 »

Если нужен только xor то его проще реализовать не привлекая quint64. Насколько понял, Вас волнует что при "наложении" этой структуры на какую-то область памяти адрес quint64 окажется не кратным 8. Не вижу почему это не должно работать. Напр
Код
C++ (Qt)
#pragma pack(push, 1)
struct Data {
char ch;
quint64 val;
};
#pragma pack(pop)
Так делать не запрещено, нечетный адрес val замедлит выполнение, но и только

Ну или рисовать геттеры/сеттеры c memmоve внутри (чтоб сердце успокоилось)
Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3260


Просмотр профиля
« Ответ #4 : Май 28, 2019, 16:12 »

Так делать не запрещено, нечетный адрес val замедлит выполнение, но и только
Я в этом не уверен Улыбающийся

Цитировать
Taking the address of a field in a #pragma packed struct does not yield a __packed pointer, so the compiler will not produce an error if you assign this address to a non-__packed pointer. However, the field might not be properly aligned for its type, and dereferencing such an unaligned pointer results in Undefined behavior.

отсюда

Но мы отвлеклись, вопрос не в том, можно ли reinterpret_cast'ить невровненные адреса. Понятно, что нельзя.
Вопрос-то про конкретный код, где мы передаем в функцию uint8[16], созданный на стеке. Он будет выровнен или нет? Мои знания говорят, что нет, но мои эксперименты на x86 этого не подтверждают - у меня не получилось создать невыровненный массив на стеке.
Записан
ViTech
Гипер активный житель
*****
Offline Offline

Сообщений: 858



Просмотр профиля
« Ответ #5 : Май 28, 2019, 17:42 »

Вопрос-то про конкретный код, где мы передаем в функцию uint8[16], созданный на стеке. Он будет выровнен или нет? Мои знания говорят, что нет, но мои эксперименты на x86 этого не подтверждают - у меня не получилось создать невыровненный массив на стеке.

Про выравнивание мало что могу точно сказать, нужно букварь больше читать. Посмотрите, как располагаются в памяти массивы с другим размером, например uint8[15]. У меня в отладчике такой не выглядит выровненным. Может конкретно uint8[16] компилятор скорей всего выровняет (и выравнивает), но не обязан это делать, на что clang и обращает внимание.

alignas в данной ситуации может помочь?
« Последнее редактирование: Май 28, 2019, 17:56 от ViTech » Записан

Пока сам не сделаешь...
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4350



Просмотр профиля
« Ответ #6 : Май 28, 2019, 21:45 »

Это бага анализатора?
Думается мне, что это именно анализатор тупит.

Или это связано с выравниванием - что никто не гарантирует выравнивание quint8 s1[16] на 8 байт?
А для чего здесь иметь обязательно выравненное значение? x86_64 может читать/писать не выравненные данные.

На x86_64 добиться левого выравнивания на стеке\маллоком не удалось...
Попробуйте так:
quint8 s1[AES_N_BLOCK+1];

плюс этот массив можно инициализировать какими-то значениями и после отработки функции посмотреть все ли в нем изменилось.
 
Update. А вот на некоторых армовских ядрах могут быть проблемы с этим. Возможно анализатор заточен на некий  общий случай.

« Последнее редактирование: Май 29, 2019, 11:24 от Old » Записан
_Bers
Бывалый
*****
Offline Offline

Сообщений: 486


Просмотр профиля
« Ответ #7 : Июнь 01, 2019, 13:39 »

Это бага анализатора?

код содержит UB.
1.
нарушение стрикт-алиасинга.

2.
нет гарантий для выравнивания.

Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3260


Просмотр профиля
« Ответ #8 : Июнь 01, 2019, 16:26 »

Это бага анализатора?

код содержит UB.
1.
нарушение стрикт-алиасинга.

2.
нет гарантий для выравнивания.



1. Верно я понимаю, что исключения для стрикт алиссинга распространяется только на void*,char*,uchar*,std::byte*?

2. Так поможет?:
Код:
struct alignas(alignof(uint64_t)) AesBlock { uchar8_t data[16]; }

Если я буду передавать const-ref структуры и возвращать копию структуры будет ок?
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #9 : Июнь 02, 2019, 07:47 »

Гарантируют - не гарантируют... Хочется чтоб "никто не подкопался" - ну просто так
Код
C++ (Qt)
namespace ns_Dummy {
 
 quint64 Get( const quint8 * addr, size_t index )
 {
   quint64 val;
   memmove(&val, addr + index * sizeof(quint64), sizeof(quin64));
   return val;
 }
 
 void Set( quint8 * addr, size_t index, quint64 val )
 {
   memmove(addr + index * sizeof(quint64), &val, sizeof(quin64));
 }
 
void copy_and_key( quint8 * dst, const quint8 * src1, quint8 * src2 )
{
   Set(dst, 0, Get(src1, 0) ^ Get(src2, 0));
   Set(dst, 1, Get(src1, 1) ^ Get(src2, 1));
}
 
}  // namespace
 
Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3260


Просмотр профиля
« Ответ #10 : Июнь 02, 2019, 12:15 »

Ну способ с memcpy понятен, только зачем, можно просто побайтовом покорить - будет быстрее, скорее всего.
Так-то велосипед писать не надо, всё уже написано за вас.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #11 : Июнь 02, 2019, 13:21 »

Ну способ с memcpy понятен,
Если понятен - то надо делать и забывать  Улыбающийся
Я давно заметил что "богатырская сила" охотно демонстрируется когда и без нее  проблем нет. А вот когда трудности и помощь была бы очень кстати - не дождесся  Плачущий
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.085 секунд. Запросов: 23.