-
- Нет, это не баг. Потому, что это UB. Потому, что изначально взяли
указатель на int и присвоили ему что-то, что не является указателем
на int (об чём есть строчка в стандарте). Далее уже не важно. Более
того, ещё раз повторю, в рамках СТАНДАРТНОГО C/C++, возникновение
такого "не бага" -- в принципе невозможно. Оно появляется из-за
"бажной" реализации упакованных структур. Ты прицепился к memcpy и
считаешь, что мол баг. Но класс проблем же НАМНОГО ШИРЕ, чем только
memcpy. fk0(858 знак., 25.07.2020 16:40)
- Вчера я прочитал что ты написал и планировал самостоятельно
поэкспериментировать. Слова это одно, а когда начинаешь разбираться
сам легко может быть другое. Не вышло, нет времени, поэтому все что
я здесь пишу основано на исходных данных этой темы. Кстати беглое
изучение документации на тему memcpy показывает что существует
большое пространство для маневра не только с тривиальными ключами
компилятора, прагмами и атрибутами но и что важно, с подключаемыми
либами/выбором obj RxTx(5329 знак., 26.07.2020 12:46)
- UB значит, что возможное дальнейшее развитие сценария писателями
компиляторов не рассматривается. Такого мол изначально не может
быть, программист не допустит. Поэтому если при анализе ситуации
возникает UB, то нет смысл думать что если то, или если это -- оно
в принципе невозможно в корректной программе. Выражение
"&IH.conag" само по себе UB. Поэтому заявить, что мол в
компиляторе баг и притягивать дальнейшие преобразования типа и
вызов memcpy не нужно: в корректной fk0(4348 знак., 26.07.2020 13:47)
- Я считаю мы с тобой обменялись мнениями. Дальше пойдет уже непринципиальное, и смысла обсуждать мелочи не вижу. Ты видимо по-инерции, все еще не осознав или невнимательно, невдумчиво прочитав мой пост, прибегнул к обсуждению стандарта C. Напрасно, так как твои посты я перечитывал несколько раз, обдумывал, и даже заметил что самое первое что ты написал в эту тему - это именно то, что memcpy должна работать без всяких проблем! А потом у тебя что-то сломалось :) Так вот, RxTx(758 знак., 26.07.2020 16:46)
- Опять за рыбу деньги. Расширение в виде #pragma pack в GCC есть?
Есть. memcpy в GCC есть? Есть. Где-нибудь в доке GCC написано, что
к элементам пакованной структуры применять memcpy нельзя? Нигде.
Бага GCC очевидна. Чего спорить-то? Хоть бы warning выдавал, как
тот же IAR делает (Used the address of unaligned structure member). - LightElf(26.07.2020 15:08)
- Именно в gcc бага нет, как и в clang последних версий. Они
применяют атрибут меняющий alignof на 1 автоматически. И там
получаются инструкции ldrb при обращении и медленная версия memcpy.
Но ты _доказать_ что это баг в keil или ранних версиях clang -- не
сможешь. Баг в чём? Я выше привёл доказательство, что это UB, a
следовательно не баг. - fk0(26.07.2020 15:27)
- Если компилятор рассматривает void* как int*, то это его
обязанность убедиться в допустимости такой замены в каждом
конкретном вызове. - LightElf(26.07.2020 15:39)
- Так для типа int -- всё корректно. Некорректно для того типа, что
лежит в упакованной структуре. Это не int, потому, что int не может
лежать на невыравненном адресе. Это другой тип. Но в структуре
записано что int, что и приводит к краху. - fk0(26.07.2020 15:43)
- Компилятор знает, что в общем случае void* нельзя приводить к int*.
Компилятор либо знает, что тип лежит в упакованной структуре и
должен генерировать правильный код. Либо компилятор не знает, где
лежит данный конкретный int и тогда должен исходить из худшего (раз
уж он поддерживает такие конструкции). А вот это "здесь читаем,
здесь не читаем, а здесь - рыбу заворачивали" есть косяк и бага. - LightElf(26.07.2020 16:22)
- Косяк и бага в том, что обычный тип int никак не может лежать в
упакованной структуре. Потому, что int не может лежать по
невыравненному адресу. С чем ты не согласен? - fk0(26.07.2020 16:26)
- Блин. Компилятор поддерживает #pragma pack(). Значит утверждение
"int не может лежать по невыровненному адресу" - для этого
компилятора ложно. Или трусы, или крестик. Или компилятор
поддерживает некую фичу и она работает как положено, или не
поддерживает. А вот это вот: "мы поддерживаем-поддерживаем, но все
никак не держится" - детский сад, штаны на лямках. - LightElf(26.07.2020 23:47)
- Ничего не значит. Int -- это конкретный тип данных, на 32-битном арме с атрибутами sizeof(int) == 4 и alignof(int) == 4. А ты хочешь тип с атрибутом aligof(type) == 1. Не может один тип данных проявлять квантовую запутанность и иметь одновременно два значения alignof! Значит это не int, это, условно, unaligned_int. А если это другой тип, это порождает массу сложностей сразу, бьющих преимущественно по программисту, хотя наверное так сделать можно. А если запутанность и fk0(735 знак., 27.07.2020 00:01)
- Блин. Компилятор поддерживает #pragma pack(). Значит утверждение
"int не может лежать по невыровненному адресу" - для этого
компилятора ложно. Или трусы, или крестик. Или компилятор
поддерживает некую фичу и она работает как положено, или не
поддерживает. А вот это вот: "мы поддерживаем-поддерживаем, но все
никак не держится" - детский сад, штаны на лямках. - LightElf(26.07.2020 23:47)
- Косяк и бага в том, что обычный тип int никак не может лежать в
упакованной структуре. Потому, что int не может лежать по
невыравненному адресу. С чем ты не согласен? - fk0(26.07.2020 16:26)
- SciFi же дал ссылку на кейловскую документацию: Taking the address of a field in a #pragma packed struct does
not yield a __packed pointer. Так что это не баг, а фичер: в структуре лежит __packed int, а
берёшь адрес, и брюки превращаются... превращаются брюки...
Идиотизм конечно, но bug report слать действительно бесполезно. - йцyкeн(26.07.2020 15:58, ссылка)
- Тут тонкость в том, что проблема будет только лишь при
разыменовании указателя. Для memcpy() тут исключение. memcpy()
принимающая void* всегда должна работать корректно при любом
значении указателя, выравнен он или не выравнен. Однако в-том то и
дело, что в данном случае без "ручного вмешательства" правильно она
не работает. - RxTx(26.07.2020 16:24)
- В ИАРе как раз "ручное вмешательство" нужно, чтобы получить
хардфолт. Функции memcpy() в ИАРе на самом деле нет, компилятор
подставляет __aeabi_memcpy или __aeabi_memcpy4. __aeabi_memcpy4 не
проверяет выравнивание, считается, что компилятор не промахнётся, и
ИАР не промахивается. Какого чёрта Кейл работает по-другому - для
меня загадка. - йцyкeн(26.07.2020 17:01)
- Угу. Понятно. - RxTx(26.07.2020 17:08)
- Натыкался в этих ваших тырнетах на список весьма доставляющих примеров undefined behavior. Там срывали покровы и открывали глаза. Советую погуглить на эту тему, можете после этого изменить мнение по поводу того, что кому чего должен и почему. - SciFi(26.07.2020 16:27)
- Проблема же уже есть и не при разыменовании указателя, а ещё на этапе компиляции, когда подставилась не та версия memcpy. Расчитанная на честный
int. - fk0(26.07.2020 16:27)
- Вот именно это ты и путаешь. Тебе стоит понять, что "еще на этапе
компиляции" в C++ это одно. Потому что "еще на этапе компиляции"
для инстанциации шаблонов это работает компилятор (и к нему
применим стандарт). А в данном случае то что ты ложно считаешь "еще
на этапе компиляции" было не при работе компилятора. СИ компилер
уже отработал. Это случилось в backend. На фазе
кодогенерации/подстановки оптимизированных инстансов memcpy. - RxTx(26.07.2020 16:55)
- Какая разница. Проблема налицо -- не соответствие типов. Уже
написали 10 раз как её вылечить, через __packed применимое к члену
структуры. Но в целом это тоже костыль, ибо нарваться можно ещё
неизвестно где. Я бы просто не использовал упакованные структуры от
греха подальше. Кроме может быть, очень тривиальных случаев и где
это даёт существенный профит в скорости, объёме памяти и т.п. - fk0(26.07.2020 17:20)
- Я тебя услышал и понял. Спасибо за приятную беседу. - RxTx(26.07.2020 17:45)
- Какая разница. Проблема налицо -- не соответствие типов. Уже
написали 10 раз как её вылечить, через __packed применимое к члену
структуры. Но в целом это тоже костыль, ибо нарваться можно ещё
неизвестно где. Я бы просто не использовал упакованные структуры от
греха подальше. Кроме может быть, очень тривиальных случаев и где
это даёт существенный профит в скорости, объёме памяти и т.п. - fk0(26.07.2020 17:20)
- Вот именно это ты и путаешь. Тебе стоит понять, что "еще на этапе
компиляции" в C++ это одно. Потому что "еще на этапе компиляции"
для инстанциации шаблонов это работает компилятор (и к нему
применим стандарт). А в данном случае то что ты ложно считаешь "еще
на этапе компиляции" было не при работе компилятора. СИ компилер
уже отработал. Это случилось в backend. На фазе
кодогенерации/подстановки оптимизированных инстансов memcpy. - RxTx(26.07.2020 16:55)
- В ИАРе как раз "ручное вмешательство" нужно, чтобы получить
хардфолт. Функции memcpy() в ИАРе на самом деле нет, компилятор
подставляет __aeabi_memcpy или __aeabi_memcpy4. __aeabi_memcpy4 не
проверяет выравнивание, считается, что компилятор не промахнётся, и
ИАР не промахивается. Какого чёрта Кейл работает по-другому - для
меня загадка. - йцyкeн(26.07.2020 17:01)
- Тут тонкость в том, что проблема будет только лишь при
разыменовании указателя. Для memcpy() тут исключение. memcpy()
принимающая void* всегда должна работать корректно при любом
значении указателя, выравнен он или не выравнен. Однако в-том то и
дело, что в данном случае без "ручного вмешательства" правильно она
не работает. - RxTx(26.07.2020 16:24)
- Компилятор знает, что в общем случае void* нельзя приводить к int*.
Компилятор либо знает, что тип лежит в упакованной структуре и
должен генерировать правильный код. Либо компилятор не знает, где
лежит данный конкретный int и тогда должен исходить из худшего (раз
уж он поддерживает такие конструкции). А вот это "здесь читаем,
здесь не читаем, а здесь - рыбу заворачивали" есть косяк и бага. - LightElf(26.07.2020 16:22)
- Так для типа int -- всё корректно. Некорректно для того типа, что
лежит в упакованной структуре. Это не int, потому, что int не может
лежать на невыравненном адресе. Это другой тип. Но в структуре
записано что int, что и приводит к краху. - fk0(26.07.2020 15:43)
- Если компилятор рассматривает void* как int*, то это его
обязанность убедиться в допустимости такой замены в каждом
конкретном вызове. - LightElf(26.07.2020 15:39)
- Именно в gcc бага нет, как и в clang последних версий. Они
применяют атрибут меняющий alignof на 1 автоматически. И там
получаются инструкции ldrb при обращении и медленная версия memcpy.
Но ты _доказать_ что это баг в keil или ранних версиях clang -- не
сможешь. Баг в чём? Я выше привёл доказательство, что это UB, a
следовательно не баг. - fk0(26.07.2020 15:27)
- Спасибо. Убедительно. - Nikolay_Po(26.07.2020 13:58)
- UB значит, что возможное дальнейшее развитие сценария писателями
компиляторов не рассматривается. Такого мол изначально не может
быть, программист не допустит. Поэтому если при анализе ситуации
возникает UB, то нет смысл думать что если то, или если это -- оно
в принципе невозможно в корректной программе. Выражение
"&IH.conag" само по себе UB. Поэтому заявить, что мол в
компиляторе баг и притягивать дальнейшие преобразования типа и
вызов memcpy не нужно: в корректной fk0(4348 знак., 26.07.2020 13:47)
- Вы заблудились в сферических абстрацкиях в ваккуме (возможно вместе
с компиляторописателями). В данном случае мы работаем на процессоре
M3 который УМЕЕТ делать unaligned access. Поэтому если компилятор
знает что генерит код для M3 то никакого undefined behavior при
невыровненном указателе на ЭТОЙ архитектуре нет - корректное
исполнение обеспечит hardware. - 3m(26.07.2020 11:42)
- К сожалению, я не пользуюсь Кейлом, поэтому про Кейл ничего не
скажу, но эксперименты с ИАРом показали следующее: во-первых, в
ИАРе воспроизвести эту ошибку не удалось. ИАР заменяет memcpy на
__aeabi_memcpy4, если адреса выронены, и на __aeabi_memcpy, если не
выровнены. Если для невыровненных адресов написать __aeabi_memcpy4
ручками, хардфолт происходит, и здесь нет никакой мистики:
__aeabi_memcpy4 использует инструкции LDM и STM, для которых CM3
как раз не умеет делать йцyкeн(109 знак., 26.07.2020 14:40)
- При пошаговом исполнении инструкции могут эмулироваться отладчиком. Я по-моему про это писал, что недостаток архитектуры ARM, существенный, отсутствие возможности пошагового исполнения, что затрудняет реализацию отладчика. На x86 есть аппаратное пошаговое исполнение, например. Ты можешь сказать, мол "поставь breakpoint после инструкции", но здесь начинаются нюансы: fk0(1712 знак., 26.07.2020 15:38)
- Умеет делать unaligned access??? Есло бы он умел, то изначально исключения (в чём собственно баг) при попытке этого самого access не возникал бы! Чтоб оно так работало надо сбросить битик UNALIGN_TRP в CCR, а компилятор ни сном, ни духом про SFR регистры и их значения. Это программист их правильно поставить должен вначале. Ну там ещё есть такая мелочь, что невыравненный доступ доступен не для всех инструкций... что тянет за собой отдельную реализацию всех библиотек fk0(267 знак., 26.07.2020 13:14, картинка)
- undefined behavior -- это йуридическое понятие, а не техническое, есличо - SciFi(26.07.2020 11:55)
- К сожалению, я не пользуюсь Кейлом, поэтому про Кейл ничего не
скажу, но эксперименты с ИАРом показали следующее: во-первых, в
ИАРе воспроизвести эту ошибку не удалось. ИАР заменяет memcpy на
__aeabi_memcpy4, если адреса выронены, и на __aeabi_memcpy, если не
выровнены. Если для невыровненных адресов написать __aeabi_memcpy4
ручками, хардфолт происходит, и здесь нет никакой мистики:
__aeabi_memcpy4 использует инструкции LDM и STM, для которых CM3
как раз не умеет делать йцyкeн(109 знак., 26.07.2020 14:40)
- Вчера я прочитал что ты написал и планировал самостоятельно
поэкспериментировать. Слова это одно, а когда начинаешь разбираться
сам легко может быть другое. Не вышло, нет времени, поэтому все что
я здесь пишу основано на исходных данных этой темы. Кстати беглое
изучение документации на тему memcpy показывает что существует
большое пространство для маневра не только с тривиальными ключами
компилятора, прагмами и атрибутами но и что важно, с подключаемыми
либами/выбором obj RxTx(5329 знак., 26.07.2020 12:46)
- Нет, это не баг. Потому, что это UB. Потому, что изначально взяли
указатель на int и присвоили ему что-то, что не является указателем
на int (об чём есть строчка в стандарте). Далее уже не важно. Более
того, ещё раз повторю, в рамках СТАНДАРТНОГО C/C++, возникновение
такого "не бага" -- в принципе невозможно. Оно появляется из-за
"бажной" реализации упакованных структур. Ты прицепился к memcpy и
считаешь, что мол баг. Но класс проблем же НАМНОГО ШИРЕ, чем только
memcpy. fk0(858 знак., 25.07.2020 16:40)