Ошибка в компиляторе? Маловероятно, но…

    Однажды мне понравилось высказывание «Думаете, что ошибка в компиляторе? Проверьте получше свой код!». Действительно, в моей практике такое случалось – когда, казалось бы, все разумные причины ошибки были отброшены и мысль о том, что вот на этот раз уж точно глюк где-то в системе, вдруг находилась какая-нибудь до смешного банальная ошибка в своем коде, сразу объясняющая все предыдущие странности.

    Но иногда все же виновным может оказаться и компилятор.


    Проект на контроллере TMS570 (одной из ключевых особенностей которого, повлиявшей на выбор, было наличие модуля с плавающей точкой). Предназначенность контроллера для safety-critical систем как бы вообще не оставляет шанса на то, что какие-то серьезные проблемы могут быть с самим контроллером. По крайней мере, в это очень хочется верить.

    В проекте присутствует весьма и весьма сложный алгоритм, требующий множества вычислений с плавающей точкой. Который, конечно же, с первой попытки реализации работать отказывается. Ничего удивительного пока, нормальный процесс разработки и отладки.

    Но дальше начинаются странности. Там, где значения вычислений ну никак не могут быть больше 1, вдруг начинает возникать ошибка «бесконечного результата». При этом попытки поймать момент, когда же это случается, не приводят к успеху.

    Финалом стало следующее: фрагмент

    if (x > 1)
    {
        printf(“%f”, x);
    }


    выдавал на печать значения вида 0.0043, т.е. сильно меньше единицы…

    И вот тут мысль о том, что «возможно, на этот раз виноват таки компилятор», вновь активизировалась. И после некоторого копания в эту сторону проблема была заподозрена, подтверждена и успешно решена.

    Дело было в том, что компилятор неправильно генерировал код входа-выхода в прерывание, не сохраняя все регистры с плавающей точкой! В результате, как только во время выполнения каких-либо вычислений с плавающей точкой случалось прерывание, внутри которого также выполнялись вычисления с плавающей точкой (а такое реально происходило!), система начинала вести себя непредсказуемым образом вроде вышеописанного. И после ручного исправления кода входа-выхода в прерывание проблема благополучно решилась и больше не проявлялась.

    ЗЫ. А когда знаешь, где же именно проблема, то уже легко можно найти, что она была известна и ранее. К сожалению, информация о ней присутствовала только на форуме TexasInstruments, и нигде не была описана в стандартной документации или среди известных проблем.

    ЗЗЫ. Что же, даже предназначенность контроллера для safety critical систем, как оказалось, не дает гарантии, что все в нем будет работать так, как заявлено…
    Ads
    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More

    Comments 10

      +5
      А может это в инструкции было? Например в линуксе ядро не сохраняет fpu контекст, и код ядра должен оборачивать вычисления с плавающей точкой в kernel_fpu_begin()/kernel_fpu_end().
        +3
        Все-таки нет, в данном случае если ты объявляешь функцию как interrupt, то ты ожидаешь от компилятора всех необходимых действий. Контекст задач в операционке тут не при чем. И производители этот баг подтвердили по ссылке выше.
        +3
        Каких граблей я в своё время только не насобирал делая маленький проектик для PIC-а. И проблемы с документацией к компилятору, и не очевидное поведение компилятора, даже аппаратные баги.
        По каким-то неведомым причинам решили всё это писать с использованием компилятора C18. Так вот, очень часто встречалось, что пример из документации отказывался работать. При ближайшем рассмотрении кода примера выяснилось, что там проверяется условие, которое всегда ложно.
        Или вот ещё, использовался PIC18F4431, там 8 каналов PWM, я использовал из них только 4, а оставшиеся пины хотел использовать как GPIO. Так эти пины во время работы PWM-а нельзя было установить в единицу. Пришлось лепить костыль: поставить подтяжки к питанию и дёргать TRIS-ы. Настраиваешь пин как вход — у тебя на выходе единица за счёт подтяжки, настраиваешь как выход — нуль. Мы долго смотрели в даташит, но нигде описания подобного поведения не обнаружили. Уж не знаю, может плохо смотрели.
          +1
          +1, тоже с микрочипом истории есть у меня.
          Правда большинство встреченных багов было в в компиляторе, в железке только парочка попалась.
          Ну а про доки говорить нечего, да, там ляпов куча.
            0
            Хрен с ними с PIC'ами. Если есть подозрение на глюк компилятора в случае gcc x86 на C++ коде, то в 60% случаев это именно так. А если он ни дай бог оптимизирует под AMD процессор, то и все 80%
          0
          Бывает что и компилятор глючит. Мы однажды ловили MSVS 2005 на том, что там BitConvert в C# неадекватно с 24 битными изображениями работает. Все остальные работали нормально, а та же процедура работала нормально на 2008 студии. Пришлось работать через 32битные…
            0
            Бывает, хотя и значительно реже, чем его в этом обвиняют. Тем интереснее ситуации, когда он глючит на самом деле.
              0
              Мне в таких случаях ассемблерный листинг помогает до максимума усеченной проблемы.
            +1
            вроде под cortex r4f есть gcc
              +2
              На архитектуре x86 тоже такое бывает, если пользоваться MMX одновременно с командами плавающей точки и не использовать инструкцию emms, которая очищает контекст FPU.

              Only users with full accounts can post comments. Log in, please.