Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: IAR 5.40.0.51500 баг в sprintf @ lpc1114/CM0
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > Cредства разработки для МК > IAR
GetSmart
Непонятный баг в виде выпадения в HardFault из sprintf при выводе форматированного float, причём в некоторых случаях. Юзал эту версию ИАРа вместе со sprintf для LPC1768 и ни на какие грабли не попадал. Стек проверял, его достаточно, оптимизация никак не влияет. Простенький кастрированный проект прилагаю для LPC1114 (без кварца) можно потестить. Прочитал все исправленные баги в версии 6.30 и не нашёл ничего об исправленном sprintf. Хотя тот же код в 6.30 не зависает, но проверил наспех. Поэтому самому интересно в чём косяк и исправлен ли он в новых версиях ИАРа.

Код
    sprintf((char *)&buf, "started\15\12");
    sendBuf(&buf[0]);

    for (uInt i=0; i<sizeof(buf); ++i) buf[i] = 0xeb;
    float freq = 82.6046981;
    sprint_flag = 10;
    sprintf((char *)&buf, "freq1=%1.5f\15\12", freq);           // <------- тут происходит падение на HardFault
    sprint_flag = 0;
    sendBuf(&buf[0]);

    sprintf((char *)&buf, "ended\15\12");
    sendBuf(&buf[0]);


Регистры на картинке взяты из режима исключения HardFault, на котором стоит бесконечный цикл.
aaarrr
Может, UNALIGN_TRP установлен?
GetSmart
Это что такое и с чем его едят?
Вообще-то я ничего с этой опцией не делал. Если по-умолчанию проц её держит в неправильном состоянии, то это ненормально. При выводе многих других значений float, например 0.0 всё работает отлично.

-----------

Упд.
Посмотрел в мануале на LPC111x. Регистр с этой опцией - RO, то бишь не меняется и бит этот всегда установлен.
aaarrr
Цитата(GetSmart @ Mar 6 2013, 04:05) *
Это что такое и с чем его едят?

Битик в Configuration Control Register, включающий abort при любом невыровненном доступе.
По умолчанию выключен, разумеется. В дизассемблере криминала нет, кроме упомянутого доступа.
Так что проверьте.
Xenia
Если буфер (buf) является массивом, то char-указатель на него записывается так:
(char *)buf
а не так:
(char *)&buf

А если же автор программы хочет обязательно куда-то вставить значок &, то пусть пишет:
(char *)&buf[0]
и это будет правильно.

Т.е. во всех функциях sprintf в качестве 1-го аргумента следует указывать (char *)buf или (char *)&buf[0], а не (char *)&buf
А покуда это не сделано, искать какие-то иные ошибки в его коде неразумно.
aaarrr
Стоп, это ж M0, а он в принципе не умеет unaligned access делать.
В опциях точно M0 стоит? Если да, тогда баг однозначно.

Цитата(Xenia @ Mar 6 2013, 04:18) *
Т.е. во всех функциях sprintf в качестве 1-го аргумента следует указывать (char *)buf или (char *)&buf[0], а не (char *)&buf
А покуда это не сделано, искать какие-то иные ошибки в его коде неразумно.

В случае массива buf и &buf - это одно и то же.
Xenia
Цитата(aaarrr @ Mar 6 2013, 04:27) *
В случае массива buf и &buf - это одно и то же.


Только в тех случаях, когда массив статический, да и то взависимости от реализации компилятора. В случаях, когда массив выделяется динамически, вы не правы во всех отношениях.
aaarrr
ОК, согласен. Но в данном конкретном случае это к проблеме ни малейшего отношения не имеет.
shreck
Попробуйте так:
Код
sprintf((char *)buf, "freq1=%1.5f\15\12", (double)freq);

Т.е. приведите аргумент freq к double.
Да, и стек должен быть на 8 выровнен (по крайней мере для CM3 это обязательно).
GetSmart
Цитата(aaarrr @ Mar 6 2013, 06:27) *
Стоп, это ж M0, а он в принципе не умеет unaligned access делать.
В опциях точно M0 стоит? Если да, тогда баг однозначно.

Да, точно М0.
Мне во всём этом интересно, что баг этот зависит от стечения многих нюансов. Например формата %1.5 в сочетании с float. Поэтому и приводить к double смысла нет. Там с тем значением плавучки идёт округление двух чисел и результат сокращается до 4 знаков после запятой. Может это что-то значит. Вообще, хотелось бы выяснить задокументирован этот баг или нет. И связь с новыми версиями компиляторов.

Почему, кстати, у многих местных модераторов есть такая привычка делать несущественные замечания. Зелтиго, Резидент, Ксюша, все страдают этим. Зелтиго в отсутствие аргументов вообще любит/л цепляться за while(1). Если конструктивно нечего сказать, то лучше промолчать. ИМХО это "болезнь", корелирующая с некой административной профнепригодностью.

В том конкретном случае &buf и &buf[0] абсолютно одинаковый код дают, т.к. буфер статический с абсолютным адресом. Меняй, не меняй каша слаще не станет.
shreck
Цитата(GetSmart @ Mar 6 2013, 09:02) *
Да, точно М0.
Мне во всём этом интересно, что баг этот зависит от стечения многих нюансов. Например формата %1.5 в сочетании с float. Поэтому и приводить к double смысла нет.

Почему, кстати, у многих местных модераторов есть такая привычка делать несущественные замечания. Зелтиго, Резидент, Ксюша, все страдают этим. Зелтиго в отсутствие аргументов вообще любит/л цепляться за while(1). Если конструктивно нечего сказать, то лучше промолчать. ИМХО это "болезнь", корелирующая с некой административной профнепригодностью.

В том конкретном случае &buf и &buf[0] абсолютно одинаковый код дают, т.к. буфер статический с абсолютным адресом. Меняй, не меняй каша слаще не станет.

Мдя.
Зачем вы вообще совета просите, если не хотите хотя бы проверить его.
Почитайте стандарт С.
GetSmart
Цитата(aaarrr @ Mar 6 2013, 06:27) *
Стоп, это ж M0, а он в принципе не умеет unaligned access делать.

Ну а допустим это был бы СМ3 со сброшенным битом UNALIGN_TRP. Он ведь всё-равно не так сохранил бы в память как умеет х86? То бишь прога не зависла бы, но значение неправильное бы выводила? Начинаю сомневаться за свои проекты, работающие в 5.40 для СМ3.

Цитата(shreck @ Mar 6 2013, 08:33) *
Мдя.
Зачем вы вообще совета просите, если не хотите хотя бы проверить его.
Почитайте стандарт С.

Прочитал. Исправил. Ничего не изменилось. Вам полегчало? Ведь это было изначально очевидно, что дело не в этом. Даже напрягаться не надо было на написание сообщений. К вам это не относится, но есть такая вещь: кто умеет - помогает, кто не умеет - цепляется. Уметь видеть нечёткое несоответствие стандарту, которое не влияет на кодогенерацию - гораздо полезнее, чем просто видеть несоответствие стандарту. Если дотошно разбирать первоначальный код, то он абсолютно верный по стандарту. Не универсальный, но верный в конкретном случае, учитывая рядом стоящее описание переменной buf. Доказывается это просто, вручную выполняя однозначный анализ компилятора. Поэтому даже отсылка в чтение стандарта является слишком безапеляционной. По поводу дабла - смысл не в том, чтобы как-нибудь обойти этот баг, а точно выяснить может ли он при каких-нибудь условиях и каких-нибудь параметрах функции появляться. Ну и конечно разобраться чей это баг.

По поводу выравнивания на 8 "внутри кода" (ака перед вызовом sprintf) - это очень непонятная мне вещь. Зачем оно? То, что внутри скрипта линкера должно быть выравнивание на 8, это есть.
shmur
А какая версия printf стоит в настройках проекта? Помню что small точно не работает с флоатом, то есть символ %f просто не раскручивается, но возможно в реализации либы для М0 там баг и все падает sm.gif Попробуйте поставить full.
aaarrr
Цитата(GetSmart @ Mar 6 2013, 06:36) *
Ну а допустим это был бы СМ3 со сброшенным битом UNALIGN_TRP. Он ведь всё-равно не так сохранил бы в память как умеет х86? То бишь прога не зависла бы, но значение неправильное бы выводила? Начинаю сомневаться за свои проекты, работающие в 5.40 для СМ3.

Нет, M3 бы отработал правильно, сохранил "как x86". В отличие от M0 он умеет.
GetSmart
Цитата(shmur @ Mar 6 2013, 11:35) *
Попробуйте поставить full.

Такая и стоит. Иначе бы он вообще никакие значения плавучки не отображал. А он отображает, когда не виснет.
GetSmart
Встал ещё на одну граблю ИАРа 5.50. Может кто-то не знает эту граблю. Если в неволатильной структуре есть поле/переменная с атрибутом volatile, и если её поллить в пустом цикле, то компилятор (как минимум на максимальной оптимизации) этот цикл вообще не поместит в коде. Как буд-то компилятор берёт (смотрит на) атрибут volatile не переменной, а целой структуры, хотя должен эти атрибуты объёдинять по функции ИЛИ. Один из вариантов бхода бага в том, чтобы вместо пустого тела цикла поставить хотя бы asm("NOP").
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.