-
- ISO/IEC 9899:201x, разделе 6.3.2.3 Pointers, параграф 7: fk0(851 знак., 24.07.2020 17:18)
- Баг в GCC, а не в Clang и вообще совершенно про противоположное,
мол нет оптимизации. Остального не понял -- научись выражать мысли
на понятном языке. Гудвин не прав, т.к. при использовании
стандартных же любых конструкций языка (без упакованных структур)
"баг" воспроизвести невозможно. А то, что он воспроизводится при
использовании упакованных структур совершенно естесственно, и
кстати в баге gcc есть на это комментарий (см. ссылку) -- вот так
проблему можно обойти. Какие fk0(1225 знак., 24.07.2020 16:56, ссылка)
- Давай укоротим проблему, насколько это возможно, т.к. нет времени и
я устал. С GCC и багом вряд ли я был прав, несмотря на то что
внутри armcc.exe v4 v5 масса строк "GCC" и отсутствует "CLANG",
armcc это отдельный компилятор. В v6 он называется armclang. Со
стандартом вышло смешно. Формально ты привел действительно ровно
то, что я спросил. И бессмысленно утверждать что разумеется вопрос
был о прямых виновниках разговора: о функции memcpy (она оговорена
в стандарте) и о 6.2 RxTx(1116 знак., 24.07.2020 22:30)
- На счёт memcpy: с одной стороны да, ты можешь подсунуть
невыравненный адрес и всё должно работать. И действительно, если ты
руками там как-то аллоцировал память, посчитал адрес, он оказался
невыравненный -- всё будет работать. Будет вызвана "неоптимальная"
версия memcpy. А в случае с гудвиновским багом компилятор был
обманут: ему сказали, что будеут копировать вот такой-то тип, а
этот тип никак не может лежать на невыравненном адресе,
следовательно, компилятор знает, если fk0(1323 знак., 25.07.2020 02:24, ссылка)
- Извини, но ты загнался. LightElf(632 знак., 26.07.2020 14:26)
- Чего ты привязался к memcpy. Я рассказал выше как получается баг. Вместо memcpy может быть любое обращение по указателю/ссылке. К слову и gcc и clang даже варнинг имеют специальный:
-Waddress-of-packed-member. Его невозможно выполнить в любом коде.
А ты хочешь сказать, мол memcpy на 32-битной машине должен
копировать по байтику вместо 4-х за раз, а на 64-битной по байтику
вместо 8, а на машинах где есть векторные инструкции... вообще
страшно. И да, оптимизатор fk0(728 знак., 26.07.2020 15:24)
- Я привязался к memcpy ровно потому, что ее параметры прямо декларируются как void*. void* означает, что указатель может быть любым. И компилятор обязан этот факт учитывать. Тяготы и лишения
компиляторописателей меня интересуют постольку-поскольку. - LightElf(26.07.2020 15:35)
- И он работает с любым типом корректно. Пока ему голову не
заморочили взятием указателя на выровненный тип в упакованной
структуре. В каком-то смысле, это недоработка компилятора, но
стандарт не нарушается. - Nikolay_Po(26.07.2020 15:39)
- Мы говорим о нестандартном (но весьма распространенном) расширении.
Причем тут ссылки стандарт? - LightElf(26.07.2020 15:42)
- ОК. С точки зрения работы расширения проблема налицо. Но fk0 принялся ругать говнокод и защищать компилятор. За что ему большое спасибо! Всё подробно разжевал, ссылки привёл. Тема была - супер!!! - Nikolay_Po(26.07.2020 15:47)
- Тогда на что ссылаться? По стандарту всё ок. А по мнению LightElf
не ок? Нужен какой-то формальный документ, который описывает
поведение компилятора. - fk0(26.07.2020 15:44)
- На документацию конкретного компилятора - LightElf(26.07.2020 15:48)
- Где в документации описывается что должно происходить в случаях: fk0(232 знак., 26.07.2020 15:59)
- А знаешь почему не описывается? Сям (компилеру и стандарту) просто
чхать, какая там структура. Осознай это. Упакованная, не
упакованная - именно сишечке по барабану. Осознай: требования по
default data alignment (вообще по типам, не только выравнивание, но
и размер) оно существует только для конкретной CPU платформы, не у
компилятора. И padding (выравнивание) структур делает не компилятор
следующий стандарту C, а бэкенд, именно он отвечает за платформу,
ее выравнивание, RxTx(223 знак., 26.07.2020 17:22)
- В пятый раз повторяю, компилятор знает и используют такое понятие
как alignof/alignas для любого типа данных, у gcc есть расширение
-- атрибут __attribute__((aligned(N))), по аналогии с typeof() есть
__alignof __(type) (в голом C, без C++). В голом C на него можно
нарваться через generics, через sizeof() тоже можно если
постараться. Именно что платформо-независимый генератор кода уже
всем этим оперирует. Отнюдь не бэкенд. - fk0(26.07.2020 17:23)
- Ты слишком поспешно тут сделал выводы насчет "уже всем этим
оперирует". Предупрежу что абсолютно точно в коде работы с
атрибутами я не разбирался (хотя по аналогии с кодом/проблемой ТС
ничто не мешает, просто лень/занятость). Все что ты перечислил -
"тонкие нити" информации, которые 11й компилер вытягивает из
констант существующих в кодогенерящем/платформозависимом BackEnd'е. RxTx(822 знак., 26.07.2020 18:12)
- Смешались в кучу люди, кони... Причём здесь бэкенд вообще и зачем знать как он устроен, если в документации, в справочнике для программиста явно сказано как оперировать этими атрибутами? Оно программисту средствами языка доступно. На самом верхнем уровне. Следовательно компилятор такими атрибутами тоже оперирует. - fk0(26.07.2020 22:21)
- Ты слишком поспешно тут сделал выводы насчет "уже всем этим
оперирует". Предупрежу что абсолютно точно в коде работы с
атрибутами я не разбирался (хотя по аналогии с кодом/проблемой ТС
ничто не мешает, просто лень/занятость). Все что ты перечислил -
"тонкие нити" информации, которые 11й компилер вытягивает из
констант существующих в кодогенерящем/платформозависимом BackEnd'е. RxTx(822 знак., 26.07.2020 18:12)
- В пятый раз повторяю, компилятор знает и используют такое понятие
как alignof/alignas для любого типа данных, у gcc есть расширение
-- атрибут __attribute__((aligned(N))), по аналогии с typeof() есть
__alignof __(type) (в голом C, без C++). В голом C на него можно
нарваться через generics, через sizeof() тоже можно если
постараться. Именно что платформо-независимый генератор кода уже
всем этим оперирует. Отнюдь не бэкенд. - fk0(26.07.2020 17:23)
- Логично, что implementation defined behaviour должен быть описан в
документации конкретного implementation. Разве не так? - LightElf(26.07.2020 17:21)
- Логично! И где, ткните меня носом! - fk0(26.07.2020 17:24)
- Я ж говорю - баг! "A conforming implementation of ISO C is required
to document its choice of behavior in each of the areas that are
designated “implementation defined”." - LightElf(26.07.2020 18:02)
- Подразумевается areas из стандарта C, а не вообще всё реализованное
компилятором. - fk0(26.07.2020 18:07)
- Большинство приличных компиляторов документируют свои расширения и
их особенности. Вот что пишет IAR: LightElf(524 знак., 27.07.2020 00:03)
- А что будет при обмене "int *" и "packed int*"
указателями/ссылками? Они не совместимы вообще? Это, то что я имею
ввиду, когда говорю, мол сделать можно, но программисту
программировать будет невозможно. - fk0(27.07.2020 00:05)
- Так уже обсуждали. Конечно, если передавать __packed int* функциям типа scanf, на некоторых архитектурах могут быть сюрпризы. Имхо, корень зла тут не в атрибуте __packed, а в функции с ... в списке параметров. - йцyкeн(27.07.2020 13:11, ссылка)
- Будет диагностика "Warning[Pa039]: use of address of unaligned
structure member". Код будет нерабочий. Что, в общем-то, и
ожидается. - LightElf(27.07.2020 00:31)
- Код будет где-то рабочий а где-то нет. На AVR рабочий, на Cortex-M3
и ESP32 рабочий а на M0 и ESP8266 получим hard fault. И варнинг
тогда уж надо выдавать в зависимости от архитектуры процессора. - 3m(27.07.2020 07:16)
- Неа. IAR этот варнинг и на CM4 выдает. Этот код непортабелен и уже потому должен вызывать варнинг. Логика должна быть такая: "ты тут чего-то странное на$%евертил, я это как-то скомпилю, но не обижайся если что". . Другое дело, что "у меня все работает", потому что выровненность полей структуры достигается другими методами (о которых компилятор не знает). - LightElf(27.07.2020 14:48)
- Код будет где-то рабочий а где-то нет. На AVR рабочий, на Cortex-M3
и ESP32 рабочий а на M0 и ESP8266 получим hard fault. И варнинг
тогда уж надо выдавать в зависимости от архитектуры процессора. - 3m(27.07.2020 07:16)
- А что будет при обмене "int *" и "packed int*"
указателями/ссылками? Они не совместимы вообще? Это, то что я имею
ввиду, когда говорю, мол сделать можно, но программисту
программировать будет невозможно. - fk0(27.07.2020 00:05)
- Большинство приличных компиляторов документируют свои расширения и
их особенности. Вот что пишет IAR: LightElf(524 знак., 27.07.2020 00:03)
- Подразумевается areas из стандарта C, а не вообще всё реализованное
компилятором. - fk0(26.07.2020 18:07)
- Я ж говорю - баг! "A conforming implementation of ISO C is required
to document its choice of behavior in each of the areas that are
designated “implementation defined”." - LightElf(26.07.2020 18:02)
- Логично! И где, ткните меня носом! - fk0(26.07.2020 17:24)
- А знаешь почему не описывается? Сям (компилеру и стандарту) просто
чхать, какая там структура. Осознай это. Упакованная, не
упакованная - именно сишечке по барабану. Осознай: требования по
default data alignment (вообще по типам, не только выравнивание, но
и размер) оно существует только для конкретной CPU платформы, не у
компилятора. И padding (выравнивание) структур делает не компилятор
следующий стандарту C, а бэкенд, именно он отвечает за платформу,
ее выравнивание, RxTx(223 знак., 26.07.2020 17:22)
- Где в документации описывается что должно происходить в случаях: fk0(232 знак., 26.07.2020 15:59)
- На документацию конкретного компилятора - LightElf(26.07.2020 15:48)
- Мы говорим о нестандартном (но весьма распространенном) расширении.
Причем тут ссылки стандарт? - LightElf(26.07.2020 15:42)
- Я выше сказал, что проблема возникает не в memcpy, а в выражении
&IH.conag. Что там после -- уже не важно. Результат данного
выражения не валиден. Он содержит корректное числовое значение, но
некорректный тип, из-за чего оптимизатор принимает не верное
решение. - fk0(26.07.2020 15:39)
- Блин. Писатели GCC сами добавили в свой компилятор поддержку упакованых структур. И не
осилили ее корректно реализовать (в отличие от других
компиляторов). А ты пытаешься убедить всех, что это не баг, а фича. - LightElf(26.07.2020 15:46)
- Вот именно в этом я и пытаюсь убедить -- что сами упакованные
структуры нихрена не продуманная "фича", страдающая множественными
дефектами и не совместимостью со стандартным языком C/C++. Поэтому
её нет в стандарте. Потому, что куда не ткнись, любое нетривиальное
использование (кроме непосредственного обращения к членам как к
значениям) -- неопределённое поведение. А как код-то писать? Шаг
влево-вправо -- "баги". - fk0(26.07.2020 16:02)
- А я тебе и говорю, что неопределенное поведение упакованных
структур - это изначально косяк стандартизаторов языка. Эта фича
есть во всех вменяемых компиляторах с лохматых времен. Наверно она
нужна зачем-то. И все ее как-то реализуют. Но пуристы в комитете
предпочитают прятать голову в песок и изобретают всякую никому не
нужную хрень, вместо введения упакованных структур в стандарт. С
описанием их конкретного поведения в разных случаях. Например,
можно указать что адрес члена LightElf(139 знак., 26.07.2020 18:00)
- В основе языка C лежит ЯВУ (B)CPL к которому добавлены системные возможности. Структуры (record, записи) в ЯВУ могут быть представлены неупорядоченными множествами. Для несистемного языка этого вполне достаточно. В С структуры появились не сразу, первые версии были без структур и Ричи сразу планировал прямое соответствие описания структур фактическому бинарному (битовому) расположению в памяти. К тому же первые версии C создавались для CISC машин, поэтому в оригинале RxTx(1382 знак., 29.07.2020 14:43)
- Косяк стандартизаторов в том, что этой недофичи попросту нет в
стандарте? Оригинально. Её и не хотят принимать, потому, что очень
много спорных моментов возникает. Значит компилятор должен уметь
генерировать код умеющийся обращаться к невыравненным данным вообще
(сейчас такой обязанности у компилятора нет). Значит объявление
такой структуры должно автоматически вводит множество типов
унаследованных от базовых (типа int), но со своим выравниванием.
Значит эти типы должны fk0(375 знак., 26.07.2020 18:06)
- Все эти спорные моменты уже давно решены и реализованы. Так или
иначе. Почему бы просто не стандартизовать ежу существующее
поведение? - LightElf(26.07.2020 18:10)
- А где задокументировано, как они решены и реализованы? Если нигде,
то что тогда стандартизировать? Я что-то не уверен, что всё прямо
так решено: в начале топика я давал ссылку -- смотри, оно
упакованный тип от неупакованного в упор не отличает. Легко это
превратить в баг. И присваивание указателей, значит, проканает без
ошибок. fk0(248 знак., 26.07.2020 22:19, ссылка, ссылка)
- ну смотри, проблема такая (паддинг, упакованные типы) существует?
существует. другие проблемы связанные с физической реализацией
работы с конкретными типами существуют? существуют. (переполнения
там, арифметика с насыщением). так почему бы хоть какое-то общее
множество не внести в стандарт? слишком уж далеко виртуальная
абстрактная машина стала абстрагироваться от существующей
физической реализации АЛУ в процессорах. - Mahagam(29.07.2020 15:28)
- Потому, что весь топик об этом. Чтоб внести в стандарт упакованные
структуры -- нужно вообще ввести новые типы данных не совместимые с
существующими (с чего баг начался). - fk0(29.07.2020 17:41)
- а может хватило бы модификатора? по типу volatile. который не меняет тип, но меняет работу с ним. Mahagam(130 знак., 30.07.2020 01:15)
- Потому, что весь топик об этом. Чтоб внести в стандарт упакованные
структуры -- нужно вообще ввести новые типы данных не совместимые с
существующими (с чего баг начался). - fk0(29.07.2020 17:41)
- ну смотри, проблема такая (паддинг, упакованные типы) существует?
существует. другие проблемы связанные с физической реализацией
работы с конкретными типами существуют? существуют. (переполнения
там, арифметика с насыщением). так почему бы хоть какое-то общее
множество не внести в стандарт? слишком уж далеко виртуальная
абстрактная машина стала абстрагироваться от существующей
физической реализации АЛУ в процессорах. - Mahagam(29.07.2020 15:28)
- А где задокументировано, как они решены и реализованы? Если нигде,
то что тогда стандартизировать? Я что-то не уверен, что всё прямо
так решено: в начале топика я давал ссылку -- смотри, оно
упакованный тип от неупакованного в упор не отличает. Легко это
превратить в баг. И присваивание указателей, значит, проканает без
ошибок. fk0(248 знак., 26.07.2020 22:19, ссылка, ссылка)
- Все эти спорные моменты уже давно решены и реализованы. Так или
иначе. Почему бы просто не стандартизовать ежу существующее
поведение? - LightElf(26.07.2020 18:10)
- А я тебе и говорю, что неопределенное поведение упакованных
структур - это изначально косяк стандартизаторов языка. Эта фича
есть во всех вменяемых компиляторах с лохматых времен. Наверно она
нужна зачем-то. И все ее как-то реализуют. Но пуристы в комитете
предпочитают прятать голову в песок и изобретают всякую никому не
нужную хрень, вместо введения упакованных структур в стандарт. С
описанием их конкретного поведения в разных случаях. Например,
можно указать что адрес члена LightElf(139 знак., 26.07.2020 18:00)
- Вот именно в этом я и пытаюсь убедить -- что сами упакованные
структуры нихрена не продуманная "фича", страдающая множественными
дефектами и не совместимостью со стандартным языком C/C++. Поэтому
её нет в стандарте. Потому, что куда не ткнись, любое нетривиальное
использование (кроме непосредственного обращения к членам как к
значениям) -- неопределённое поведение. А как код-то писать? Шаг
влево-вправо -- "баги". - fk0(26.07.2020 16:02)
- Блин. Писатели GCC сами добавили в свой компилятор поддержку упакованых структур. И не
осилили ее корректно реализовать (в отличие от других
компиляторов). А ты пытаешься убедить всех, что это не баг, а фича. - LightElf(26.07.2020 15:46)
- И он работает с любым типом корректно. Пока ему голову не
заморочили взятием указателя на выровненный тип в упакованной
структуре. В каком-то смысле, это недоработка компилятора, но
стандарт не нарушается. - Nikolay_Po(26.07.2020 15:39)
- Я привязался к memcpy ровно потому, что ее параметры прямо декларируются как void*. void* означает, что указатель может быть любым. И компилятор обязан этот факт учитывать. Тяготы и лишения
компиляторописателей меня интересуют постольку-поскольку. - LightElf(26.07.2020 15:35)
- Чего ты привязался к memcpy. Я рассказал выше как получается баг. Вместо memcpy может быть любое обращение по указателю/ссылке. К слову и gcc и clang даже варнинг имеют специальный:
-Waddress-of-packed-member. Его невозможно выполнить в любом коде.
А ты хочешь сказать, мол memcpy на 32-битной машине должен
копировать по байтику вместо 4-х за раз, а на 64-битной по байтику
вместо 8, а на машинах где есть векторные инструкции... вообще
страшно. И да, оптимизатор fk0(728 знак., 26.07.2020 15:24)
- Опыт жизни и общефилософское наблюдение показывают: дискуссия
(разговор, беседа) только тогда здрава, заканчивается познавательно
и позитивно, когда ее участники имеют одну и ту же цель и
заинтересованы в одном и том же результате. Моя цель в данном
случае - выяснить четкую практическую истину. Где что сломалось,
почему, кто виноват и что делать. Твоя цель явно в том чтобы либо
образовать меня/нас, либо просто изложить (насколько ты понимаешь и
способен) свои представления о RxTx(484 знак., 25.07.2020 10:11)
- Нет, это не баг. Потому, что это 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)
- Отдыхать вам, батенька, надо... Компилятор должен делать то, что
ему явно указали. Все. Конец пустому пиздежу... - Гyдвин(25.07.2020 08:43)
- Иди в багтрекер clang и попробуй там завести баг. И посмотри как
далеко тебя пошлют. fk0(122 знак., 25.07.2020 14:07)
- Кто сказал, что в багтрекере шланга нет пидарасов? Давайте
заслушаем правду-матку на похожую тему от простого парня из народа
Л.Торвальдса: SciFi(257 знак., 25.07.2020 17:42, ссылка)
- Причём тут мнение какого-то Торвальдса, причём по совершенно другому вопросу? Кто такой этот Торвальдс вообще? Почему его мнение, тем более по другому вопросу, меня должно волновать? Он может выразить как-то аргументированную точку зрения? Нет, он обозвал всех duckheads потому, что он мол особенный. Сам он duckhead. - fk0(25.07.2020 19:23)
- Кто сказал, что в багтрекере шланга нет пидарасов? Давайте
заслушаем правду-матку на похожую тему от простого парня из народа
Л.Торвальдса: SciFi(257 знак., 25.07.2020 17:42, ссылка)
- Иди в багтрекер clang и попробуй там завести баг. И посмотри как
далеко тебя пошлют. fk0(122 знак., 25.07.2020 14:07)
- Извини, но ты загнался. LightElf(632 знак., 26.07.2020 14:26)
- Я привожу в пример C++ потому, что зная как он работает начинает
приоткрываться принцип работы и C компилятора тоже (благо внутри
там у GCC и Clang для обоих языков один "движок"). В языке C нет
некоторых вещей (шаблонов, ADL), что не даёт понять, например,
почему тип важен и как тип может управлять компиляцией. Для C
программиста может быть не очевидно, а C++ программист запросто
может написать свой самодельный memcpy ровно с такими же "багами"
пользуясь только средствами fk0(196 знак., 25.07.2020 01:57, ссылка)
- Не надо в простой как грабли и предсказуемый C тянуть угар из плюсов. memcpy простейшая фунцкия с нетипизированными указтелями и не надо сюда вносить лишние сущности! Если хотите типизированный xxxcpy он должен быть объявлен как-то так: intcpy(int* src, int* dst, size_t item_count) - 3m(25.07.2020 10:17)
- На счёт memcpy: с одной стороны да, ты можешь подсунуть
невыравненный адрес и всё должно работать. И действительно, если ты
руками там как-то аллоцировал память, посчитал адрес, он оказался
невыравненный -- всё будет работать. Будет вызвана "неоптимальная"
версия memcpy. А в случае с гудвиновским багом компилятор был
обманут: ему сказали, что будеут копировать вот такой-то тип, а
этот тип никак не может лежать на невыравненном адресе,
следовательно, компилятор знает, если fk0(1323 знак., 25.07.2020 02:24, ссылка)
- Давай укоротим проблему, насколько это возможно, т.к. нет времени и
я устал. С GCC и багом вряд ли я был прав, несмотря на то что
внутри armcc.exe v4 v5 масса строк "GCC" и отсутствует "CLANG",
armcc это отдельный компилятор. В v6 он называется armclang. Со
стандартом вышло смешно. Формально ты привел действительно ровно
то, что я спросил. И бессмысленно утверждать что разумеется вопрос
был о прямых виновниках разговора: о функции memcpy (она оговорена
в стандарте) и о 6.2 RxTx(1116 знак., 24.07.2020 22:30)