Прямо сейчас я нахожусь в командировке в Беларуси, и поймал странное поведение программы, проявляющееся после 20-30 секунд работы девайса на STM32.

У меня в программе есть энумератор, который может принимать только три значения, от 0 до 2:

Снимок экрана 2015-12-21 в 14.45.13

Однако, при отладке оказалось что в этой переменная лежит 0x72, вот скриншот окна Watch:

Снимок экрана 2015-12-21 в 14.46.14

Как так? Ещё и на осциллографе какая-то фигня вместо нормальных посылок на UART, который обрабатывается вообще в другом месте кода.

Открываем map-файл. printer_type лежит по адресу 0x200002a3. Смотрим память.

Снимок экрана 2015-12-21 в 14.48.01

Ясно, его затёр мусор, начинающийся примерно в 0x20000214. Опять смотрим map.

Вот он, массив databuf_BA.

Снимок экрана 2015-12-21 в 14.49.23

Но он имеет длину 50.

Снимок экрана 2015-12-21 в 14.50.10

Найдём, где массив заполняется. Так и есть, мы просто идём по массиву подряд, не проверяя границы.

Снимок экрана 2015-12-21 в 14.50.46

Когда я писал это место, я надеялся что received_count (сбрасывающийся немного дальше) никогда не превысит не то, что 50, а даже 20. Зря надеялся, ошибки могут возникать везде.

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

Снимок экрана 2015-12-21 в 18.47.02

 

Вот так, из-за характера расположения переменных в памяти, и того что C не контролирует переполнение — ошибка в одном месте портит что-то в совершенно другом месте. Это — классический пример сильной связности кода на C.