Обзор продукции Espressif.
Чипы, модули и программное обеспечение Espressif разрабатывается большой международной командой квалифицированных разработчиков.
В январе 2018 года компания Espressif Systems (Шанхай, Китай) – лидер в области разработки и производства высокопроизводительных маломощных Wi-Fi и Wi-Fi / Bluetooth- решений – произвела и продала 100-миллионный чип IoT, подтвердив своё лидерство на рынке IoT. Чипированные и модульные решения компании отмечены многочисленными наградами крупных промышленных форумов и потребительских ассоциаций.
Выпуск в 2014 году SoC (System-on-a-Chip) чипа ESP8266 был признан поворотным моментом для мирового рынка IoT. Эффект ESP8266 был повторен выпуском текущего флагманского SoC-чипа ESP32 в 2016 году, ставшего самым интегрированным Wi-Fi и двухрежимным Bluetooth-чипом в индустрии IoT.
Сегодня решения Espressif используются во многих популярных высокотехнологичных продуктах, от планшетов, телевизионных приставок, управляющих устройств до интеллектуальных приборов освещения и климат-контроля HVAC. Чипы Espressif – основа высокозащищенных профессиональных решений, таких как камеры наблюдения, механизмы контроля доступа, телеметрические системы, сенсорные сети и роботы.
Espressif совершила революцию в IoT, предоставив открытый доступ к своим кодам. Продолжением этого подхода стали платформы разработки программного обеспечения IoT – ESP-IDF и ESP-ADF, позволяющие создавать в их средах многочисленные клиентские проекты и платформы.
Содержание:
Двухъядерные модули Wi-Fi с Dual-mode Bluetooth
Модули содержат два независимых ядра CPU с регулируемой тактовой частотой от 80 МГц до 240 МГц.
До +19,5 дБм на выходе антенны обеспечивает устойчивость радиоканала даже в неблагоприятных условиях приёма. Классический Bluetooth для устаревших подключений, поддерживающий профили L2CAP, SDP, GAP, SMP, AVDTP, AVCTP, A2DP (SNK) и AVRCP (CT). Поддержка профилей низкой мощности Bluetooth (BLE), включая профили L2CAP, GAP, GATT, SMP и GATT, такие как BluFi, SPP-like и т. д. Bluetooth Low Energy (BLE) подключается к смартфонам, передавая низкоэнергетические сигналы-маяки для легкого обнаружения.
Ток в режиме сна составляет менее 5 мкА, что делает эти модули максимально пригодными для использования в устройствах с батарейным питанием (компактные носимые устройства и закладки).
Интегрированная флэш-память 4 МБ.
Периферийные устройства включают емкостные сенсорные датчики, датчик Холла, малошумящие усилители сигнала, интерфейс SD-карты, Ethernet, высокоскоростной SPI, UART, I2S и I2C.
Полностью сертифицированные модификации, в т.ч. со встроенными антеннами и специализированными программными стеками.
Флагман линейки – модуль ESP-WROOM-32 на плате 25,2х18 мм. Содержит чипсет ESP32 SoC, флэш-память, прецизионные дискретные компоненты и антенну на PCB, обеспечивающие выдающиеся радиочастотные характеристики в приложениях с ограниченным объемом. Схемное решение модуля и оптимизированная компоновка его четырехслойной печатной платы доступны для скачивания на сайте производителя и могут использоваться в качестве исходной справочной информации для разработки собственных аппаратных решений на основе ESP32.
Модуль ESP-WROVER, с 4,5 МБ ОЗУ и двухъядерным процессором 240 МГц, нацелен на высокие требования к производительности. Создавайте интернет-камеры, интеллектуальные дисплеи, системы голосового управления или интернет-радиоприемники с помощью этого высокоинтегрированного сверхмощного модуля, подключая к нему ЖК-дисплеи, камеры, микрофоны и кодеки.
| Модуль | Описание | Чип | Размеры (мм) | Pins | Flash (МБ) | PSRAM (MБ) | Антенна | Отладочное средство |
|---|---|---|---|---|---|---|---|---|
![]() ESP32-WROOM-32 в каталоге | ESP-WROOM-32 содержит ESP32 SoC, флэш-память, высокоточные дискретные компоненты и PCB- антенну, которая обеспечивает выдающиеся радиочастотные характеристики в приложениях с ограниченным объемом. | ESP32- D0WDQ 6 | 18×25.5×3.1 | 38 | 4 | N / A | Антенна PCB, 2 дБи | ESP32-DevKitC |
![]() ESP32-WROOM-32D в каталоге | ESP-WROOM-32D базируется на ESP32- D0WD и предназначен для широкого спектра приложений, от маломощных сенсорных сетей, до самых сложных задач, таких как голосовое кодирование, потоковое воспроизведение музыки и декодирование MP3. | ESP32- D0WD | 18×25.5×3.1 | 38 | 4 | N / A | Антенна PCB, 2 дБи | ESP32-DevKitC |
![]() ESP32-WROOM-32U в каталоге | ESP32-WROOM-32U базируется на ESP32- D0WD. Оборудован разъемом U.FL. | ESP32- D0WD | 18×19.2×3.2 | 38 | 4 | N / A | Антенна IPEX | ESP32-DevKitC |
![]() ESP32-WROVER в каталоге | ESP32-WROVER имеет встроенную SPI-память 4 Мбайт и встроенную PSRAM 8 МБ, ориентирован на широкий спектр приложений. Предустановленная прошивка отсутствует. | ESP32- D0WDQ 6 | 18×31.4×3.3 | 38 | 4 | 8 | Антенна PCB, 2 дБи | ESP-WROVER-KIT, ESP32-LyraT, ESP32-LyraTD-MSC |
![]() ESP32-WROVER-I в каталоге | ESP32-WROVER-I оборудован разъемом U.FL. Модуль имеет встроенную SPI-память 4 МБ и встроенную PSRAM 8 МБ, ориентирован на широкий спектр приложений. Предустановленная прошивка отсутствует. | ESP32- D0WDQ 6 | 18×31.4×3.3 | 38 | 4 | 8 | Антенна IPEX | N / A |
![]() ESP32-WROVER-B в каталоге | ESP32-WROVER-B имеет встроенную SPI- память 4 Мбайт и встроенную PSRAM 8 МБ, ориентирован на широкий спектр приложений, начиная от маломощных сенсорных сетей и заканчивая такими сложными задачами, как голосовое управление и кодирование, потоковое воспроизведение музыки и декодирование MP3. Предустановленная прошивка отсутствует. | ESP32- D0WD | 18×31.4×3.3 | 38 | 4 | 8 | Антенна PCB, 2 дБи | ESP32-DevKitC, ESP-WROVER-KIT-VB и ESP32-Azure IoT Kit в каталоге |
ESP32-WROVER-IB в каталоге | ESP32-WROVER-IB оборудован разъемом U.FL. Модуль имеет встроенную SPI-память 4 МБ и встроенную PSRAM 8 МБ, ориентирован на широкий спектр приложений, от маломощных сенсорных сетей до самых сложных задач, таких как голосовое управление и кодирование, потоковое воспроизведение музыки и декодирование MP3. Предустановленная прошивка отсутствует. | ESP32- D0WD | 18×31.4×3.3 | 38 | 4 | 8 | Антенна IPEX | ESP32-DevKitC, ESP-WROVER-KIT-VB |
![]() ESP32-PICO-D4 в каталоге | ESP32-PICO-D4 — это модуль System-in- Package (SiP), который интегрирует все периферийные компоненты, включая кварцевый генератор, память, фильтрующие конденсаторы и RF- часть в едином пакете. Модуль имеет флэш- память SPI объемом 4 Мбайт. | ESP32 | 7x7x0.94 | 48 | 4 | N / A | N / A | ESP32-PICO-KIT |
Одноядерные модули с Wi-Fi и Dual-mode Bluetooth
Летом 2018 года начат серийный выпуск первого в этой линейке модуля ESP32-SOLO-1 (встроенный чипсет ESP32-S0WD на базе высокопроизводительного одноядерного процессора с тактовой частотой 160 МГц).
ESP32-SOLO-1 – мощный, универсальный Wi-Fi+Bluetooth v4.2 BR/EDR & BLE модуль, предназначенный для широкого спектра приложений. Модуль построен на чипе ESP32-S0WD и имеет стандартный набор интерфейсов – GPIO, SD, SPI, I2C, UART, ADC/DAC, LED PWM, Motor PWM.
До +19,5 дБм на выходе антенны обеспечивает хорошие показатели устойчивости радиоканала.
Классический Bluetooth для устаревших подключений, также поддерживающий L2CAP, SDP, GAP, SMP, AVDTP, AVCTP, A2DP (SNK) и AVRCP (CT). Поддержка профилей низкой мощности Bluetooth Low Energy (BLE), включая профили L2CAP, GAP, GATT, SMP и GATT, а также такие как BluFi, SPP-like и т. д. BLE подключается к смартфонам, передавая низкоэнергетические маяки для легкого обнаружения.
Потребляемый ток в режиме сна составляет менее 5 мкА, что делает этот модуль пригодным для применения в приложениях с батарейным питанием (автономные датчики и закладки) и в компактных носимых устройствах.
Модуль предназначен для широкого спектра приложений, начиная от маломощных сенсорных сетей и заканчивая самыми сложными задачами, такими как голосовое управление и кодирование, потоковое воспроизведение музыки и декодирование MP3.
Периферийные устройства и интерфейсы включают емкостные сенсорные датчики, датчик Холла, малошумящие усилители сигнала, интерфейс SD-карты, Ethernet, высокоскоростной SPI, UART, I2S и I2C.
| Модуль | Описание | Чип | Размеры (мм) | Pins | Flash (МБ) | PSRAM (MБ) | Антенна | Отладочное средство |
|---|---|---|---|---|---|---|---|---|
![]() ESP32-SOLO-1 в каталоге | ESP32-SOLO-1 содержит ESP32 SoC, флэш-память, высокоточные дискретные компоненты и PCB- антенну, которая обеспечивает выдающиеся радиочастотные характеристики в приложениях с ограниченным объемом. | ESP32- S0WD | 18×25.5×3.1 | 38 | 4 | N / A | Антенна PCB, 2 дБи | ESP32-DevKitC |
Интеграция Bluetooth, Bluetooth LE и Wi-Fi гарантирует универсальность модуля и возможность его использования в самом широком спектре приложений: от простых клиентских приложений до прямого подключения к Интернету через Wi-Fi. При использовании Bluetooth возможно удобное подключение пользователя к телефону или передача низкоэнергетических радиомаяков для обнаружения модуля и его последующей активации. Реальная чувствительность приемника от –98 дБм (при DSSS, 1 Мбит/с).
Операционная система ESP32-freeRTOS с LwIP; TLS 1.2 со встроенным аппаратным ускорением. Также поддерживаются протоколы безопасности (шифрация) в эфире (OTA), благодаря которым разработчики могут обновлять свои продукты удаленно (даже после их выпуска) с минимальными затратами и усилиями.
Пины SCK/CLK, SDO/SD0, SDI/SD1, SHD/SD2, SWP/SD3 и SCS/CMD, а именно GPIO6-GPIO11, подключены к SPI-flash памяти, встроенной в ESP32-SOLO-1, и не рекомендуются к использованию для других целей.
Одноядерные модули с 802.11b/g/n 2.4 ГГц Wi-Fi
Маломощные, высокоинтегрированные решения Wi-Fi на чипсете ESP8266EX, интегрирующего 32-разрядный одноядерный микроконтроллер Tensilica L106 (MCU), обеспечивающий сверхнизкое энергопотребление, 16- разрядный RSIC, поддержка тактовой частоты до 160 МГц. Дизайн с минимумом внешних компонентов (до 7). До +19,5 дБм на выходе антенны обеспечивает хорошие условия ведения связи в сложной помеховой обстановке. Потребляемый ток в режиме сна составляет менее 20 мкА, что делает эти модули пригодными для использования в устройствах с батарейным питанием и в носимых устройствах.
Периферийные устройства могут подключаться через UART, GPIO, I2C, I2S, SDIO, PWM, ADC и SPI.
Благодаря интегрированной операционной системе реального времени (RTOS) и функциональному стеку Wi-Fi, около 80% вычислительной мощности контроллера чипсета ESP8266EX доступно для программирования и разработки пользовательских приложений.
| Модуль | Описание | Чип | Размеры (мм) | Pins | Flash (МБ) | PSRAM (MБ) | Антенна | Отладочное средство |
|---|---|---|---|---|---|---|---|---|
![]() ESP-WROOM-02 в каталоге | ESP-WROOM-02 модуль на базе ESP8266EX. Имеет широкий температурный диапазон (-40°C … 85°C) (-40°C … 125°C, доступен по индивидуальному заказу). | ESP8266 EX | 18x20x3 | 18 | 2 | N / A | Антенна PCB, 2 дБи | ESP-Launcher |
ESP-WROOM-02D в каталоге | ESP-WROOM-02D модуль на базе ESP8266EX, имеет оптимизированную радиочастотную характеристику. Температурный диапазон (-40°C … 85°C) | ESP8266 EX | 18x20x3.2 | 18 | 2 | N / A | Антенна PCB, 2 дБи | ESP8266-DevKitC |
![]() ESP-WROOM-02U в каталоге | ESP-WROOM-02U модуль на основе ESP8266EX, с оптимизированной работой радиоканала. Для подключения антенны имеет разъем U.FL. Температурный диапазон (-40°C … 85°C) | ESP8266 EX | 18×14.3×3.2 | 18 | 2 | N / A | Антенна IPEX | ESP8266-DevKitC |
![]() ESP-WROOM-S2 в каталоге | ESP-WROOM-S2 может работать как slave SDIO / SPI, при этом скорость SPI составляет до 8 Мбит/с. Модуль имеет широкий температурный диапазон (-40 ° C 125 ° C). Доступен по индивидуальному заказу. | ESP8266 EX | 16x23x3 | 20 | 2 | N / A | Антенна PCB, 2 дБи | N / A |
Модули сертифицированы, в т.ч. в модификациях со встроенными антенными и специализированными программными стеками.
Отладочные платы для модулей Wi-Fi+BT/BLE (диапазон 2.4 ГГц)
Отладочные платы компании Espressif – это все, что вам нужно для разработки ваших собственных приложений IoT.
Espressif IoT Development Framework: 71 выстрел в ногу
Один из наших читателей обратил наше внимание на Espressif IoT Development Framework. Он нашёл ошибку в коде проекта и поинтересовался, смог бы её найти статический анализатор PVS-Studio. Именно эту ошибку анализатор пока найти не может, зато нашёл множество других. По мотивам этой истории и найденных ошибок, мы решили написать классическую статью про проверку открытого проекта. Приятного изучения того, из-за чего IoT устройства могут «выстрелить вам в ногу».
Программно-аппаратные системы
Отец языка C++ Бьярне Страуструп как-то сказал:
«Си» позволяет очень просто выстрелить себе в ногу. На «Си++» сделать это сложнее, но, когда вы это делаете, отрывает всю ногу.
В нашем случае, заявление начинает приобретать несколько иной смысл. Из идеи, что программист может ошибиться и программа будет функционировать как-то неправильно, мы подходим к ситуациям, когда это может причинять реальный физический вред.
Такие проекты, как Espressif IoT Development Framework, служат для реализации программно-аппаратных систем, взаимодействующих с человеком и управляющие объектами в реальном мире. Всё это накладывает дополнительные требования к качеству и надёжности программного кода. Именно отсюда берут основы такие стандарты как MISRA или AUTOSAR. Впрочем, это уже другая тема.
Вернёмся к Espressif IoT Development Framework (исходный код на сайте GitHub: esp-idf). Вот его краткое описание:
ESP-IDF is Espressif’s official IoT Development Framework for the ESP32 and ESP32-S series of SoCs. It provides a self-sufficient SDK for any generic application development on these platforms, using programming languages such as C and C++. ESP-IDF currently powers millions of devices in the field, and enables building a variety of network-connected products, ranging from simple light bulbs and toys to big appliances and industrial devices.
Думаю, читателям интересно посмотреть, уделяется ли разработчиками этого проекта достаточно внимания к качеству и надёжности. К сожалению, такой уверенности, нет. Познакомившись со статьей и описанием замеченных дефектов, вы поймете мои опасения. Итак, заваривайте чай/кофе, вас ждёт много текста и кода.
Предыстория
Ещё хочется рассказать, как появилась эта статья. Мне написал Юрий Попов (Hardcore IoT fullstack dev & CTO), который с интересом следит за нашими публикациями. Незадолго до этого он самостоятельно вручную нашёл ошибку в Espressif IoT Development Framework и поинтересовался, может ли выявить этот дефект PVS-Studio. Ошибка связана с опечаткой в коде, а PVS-Studio всегда славился тем, что хорошо выявляет подобные ошибки.
Некорректный код находился в файле mdns.c:
Происходит обход списка и определённым образом должны суммироваться длины строк, на которые ссылаются различные объекты, хранящиеся в списке. Вот только всё время считается длина строк, хранящаяся в первом объекте.
К обоюдному разочарованию меня и читателя Юры, PVS-Studio не смог заметить эту ошибку. Он просто не знает про такой паттерн ошибки. Собственно, и наша команда не знала про такой паттерн. PVS-Studio, как и любой другой анализатор, умеет замечать только то, на что его запрограммировали :).
Что ж, жаль, но не страшно. Это один из источников, где можно черпать идеи по развитию PVS-Studio. Пользователи и клиенты присылают различные паттерны ошибок, которые они выявили в коде своих проектов, но про которые не знает PVS-Studio. И мы постепенно создаём новые диагностические правила. Так произойдёт и с рассмотренным выше паттерном. Мы уже выписали этот пример в TODO и реализуем новое диагностическое правило для выявления схожих ситуаций в одной из следующих версий анализатора.
По итогам всего этого, Юра сам написал небольшую заметку про эту ошибку, как он её искал и про PVS-Studio: «Баг в ESP-IDF: MDNS, Wireshark и при чём тут единороги». Плюс он уведомил авторов проекта о найденной ошибке: Spurious MDNS collision detection (IDFGH-4263).
На этом история не закончилось. Юра предложил нашей команде проверить проект и написать заметку о результатах. Мы не стали отказываться, так как весьма часто делаем подобные публикации для популяризации методологии статического анализа кода и заодно инструмента PVS-Studio :).
Правда проверку мы повели достаточно неуклюже. К сожалению, нет примера «собрать всё». Ну или мы не разобрались. Мы начали с getting_started\hello_world. Вроде бы он использует часть фреймворка, но не полностью. Так что можно найти и другие ошибки, добившись компиляции большего количества файлов фреймворка. Другими словами, то, что в статье будет описана только 71 ошибка, — это наша недоработка :).
Надо понимать, что у меня не было задачи найти как можно больше ошибок. Поэтому, когда я бегло пробежался по неполному отчёту, я сразу понял, что материала и так более чем достаточно для статьи. Поэтому я поленился углубляться в дальнейшее изучение проекта.
К счастью, у Юрия Попова, который заварил всю эту кашу, гораздо больше энтузиазма, чем у меня. Он сообщил, что смог добиться более полной компиляции фреймворка и проверил гораздо больше файлов. И, очень вероятно, вслед за моей статьей, выйдет его статья, где он рассмотрит дополнительную порцию ошибок.
Примеры, откуда берутся ложные/бессмысленные срабатывания
Всех исследователей, которые захотят проверить Espressif IoT Development Framework, я хочу предупредить, что понадобится предварительная настройка анализатора. Без неё вы утонете в большом количестве ложных/бесполезных срабатываний. Но анализатор не виноват.
В коде проекта очень активно используются директивы условной компиляции (#ifdef) и макросы. Такой стиль кодирования запутывает анализатор и порождает множество однотипных бесполезных предупреждений. Чтобы было понятнее, как и почему это происходит, рассмотрим пару примеров.
Выбран такой режим компиляции, при котором макрос CONFIG_GATTS_ENABLE не объявлен. Поэтому, для анализатора этот код выглядит так:
Анализатор вроде прав, что условие всегда истинно. С другой стороны, пользы от этого предупреждения нет, так как мы понимаем, что код совершенно корректен и имеет смысл. Подобные ситуации встречаются крайне часто, что затрудняет просмотр отчёта. Это такая неприятная плата за активное использование условной компиляции :).
С одной стороны, анализатор прав. Но всё поменяется, если макрос в другом режиме компиляции будет раскрыт в «ничто». В этом случае проверка уже будет иметь смысл. Да, при втором сценарии анализатор ругаться не будет, но сути это уже не меняет. В первом то случае у нас лишнее предупреждение.
Впрочем, всё это не страшно. Если взяться за проект всерьез, то можно настроить анализатор так, что большинство бессмысленных сообщений исчезнет. Ещё в ряде мест можно улучшить ситуацию, изменив стиль написания кода и макросов. Но это уже выходит за рамки данной статьи. Дополнительно можно использовать механизм подавления предупреждений в конкретных местах, в макросах и т.д. Есть ещё и механизм массовой разметки. Про всё это подробнее можно почитать в статье «Как внедрить статический анализатор кода в legacy проект и не демотивировать команду».
Security
Начнём с предупреждений, которые, на мой взгляд, связаны с темой security. Разработчики операционных систем, фреймворков и других подобных проектов, должны с особенным вниманием относиться к поиску слабостей кода, которые потенциально могут приводить к возникновению уязвимостей.
Для удобства классификации слабостей кода можно использовать CWE (Common Weakness Enumeration). В PVS-Studio можно включить отображение CWE ID для предупреждений. Для предупреждений этой главы я дополнительно приведу соответствующий CWE ID.
Ошибка N1; Порядок аргументов
Предупреждение PVS-Studio: V764 Possible incorrect order of arguments passed to ‘crypto_generichash_blake2b__init_salt_personal’ function: ‘salt’ and ‘personal’. blake2b-ref.c 457
При вызове функции blake2b_init_salt_personal перепутаны местами аргументы personal и salt. Мне кажется, вряд ли это задумано специально и, скорее всего, это ошибка, возникшая по невнимательности. Я не ориентируюсь в коде проекта и в криптографии, но что-то мне подсказывает, что такая путаница может иметь нехорошие последствия.
Согласно CWE эта ошибка классифицируется как CWE-683: Function Call With Incorrect Order of Arguments.
Ошибка N2; Отбрасывание значащих бит
Предупреждение PVS-Studio: V642 Saving the ‘memcmp’ function result inside the ‘unsigned char’ type variable is inappropriate. The significant bits could be lost breaking the program’s logic. mbc_tcp_master.c 387
Сохранять результат работы функции memcmp в однобайтовую переменную — это очень плохо. Это дефект, который вполне может превратиться в реальную уязвимость, подобную этой: CVE-2012-2122. Подробнее, почему так писать нельзя, описано в документации к диагностике V642.
Согласно CWE эта ошибка классифицируется как CWE-197: Numeric Truncation Error.
Ошибка N3 — N20; Приватные данные остаются в памяти
Предупреждение PVS-Studio: V597 The compiler could delete the ‘memset’ function call, which is used to flush ‘prk’ buffer. The memset_s() function should be used to erase the private data. dpp.c 854
Очень распространённая ошибка. Компилятор вправе в целях оптимизации удалить вызов функции memset, так как после заполнения буфера нулями, он больше не используется. В результате приватные данные на самом деле не затираются, а продолжат болтаться где-то в памяти. Подробности можно узнать в статье «Безопасная очистка приватных данных».
Согласно CWE эта ошибка классифицируется как CWE-14: Compiler Removal of Code to Clear Buffers.
Другие ошибки этого типа:
Ошибка N21; Не удаляется буфер с приватными данными
Предупреждение PVS-Studio: V575 The null pointer is passed into ‘free’ function. Inspect the first argument. sae.c 1185
Если с паролем что-то не так и указатель pw_id не нулевой, то выводится отладочное предупреждение и функция завершает свою работу. Что интересно, далее происходит попытка освободить буфер, используя нулевой указатель. Более того, в нулевой указатель вновь записывается NULL. Всё это не имеет смысла. Скорее всего, строчки освобождения памяти находятся не на своём месте. И мне кажется, код должен быть таким:
Во-первых, наверное, это устранит утечку памяти. Во-вторых, приватные данные перестанут где-то зря храниться длительное время в памяти.
Согласно CWE, эта формально ошибка классифицируется как CWE-628: Function Call with Incorrectly Specified Arguments. Так её классифицирует PVS-Studio, но, по сути и последствиям, это какая-то другая слабость кода.
Ошибка N22, N23; Использование неинициализированного буфера в качестве ключа
Предупреждение PVS-Studio: V614 Uninitialized buffer ‘hex’ used. Consider checking the second actual argument of the ‘memcpy’ function. wps_registrar.c 1657
Неинициализированный буфер hex используется для инициализации какого-то ключа. Зачем так сделано — непонятно. Возможно, это попытка заполнить ключ какими-то случайным значением, но всё равно это очень плохой способ.
В любом случае этот код нуждается во внимательной проверке.
Согласно CWE, эта ошибка классифицируется как CWE-457: Use of Uninitialized Variable.
Аналогичная ошибка: V614 Uninitialized buffer ‘hex’ used. Consider checking the second actual argument of the ‘memcpy’ function. wps_registrar.c 1678
Опечатки и Copy-Paste
Ошибка N24; Copy-Paste классический
Предупреждение PVS-Studio: V523 The ‘then’ statement is equivalent to the ‘else’ statement. timer.c 292
Есть подозрение, что строчку скопировали, но забыли что-то в ней изменить. В результате, независимо от условия, в переменную intr_source записывается одно и тоже значение.
Примечание. Бывает конечно, что так и задумано. Например, если пока, значения действительно должны совпадать (т.е. это «todo-код»). Но тогда такой код явно стоит снабдить поясняющим комментарием.
Ошибка N25; Не там поставлена скобка
Приоритет оператора сравнения выше, чем приоритет оператора присваивания. Поэтому условие вычисляется следующим образом:
В принципе, ошибочная ситуация поймается и обработается в коде, но не так, как задумано. Предполагалось распечатывать статус ошибки, который хранится в переменной ret. Но значение ret всегда будет равно 0 или 1. Поэтому, если что-то пойдёт не так, всегда будет распечатываться только одно значение (-1).
Ошибка возникла из-за того, что не там поставлена скобочка. Правильный код:
Теперь всё будет вычисляться как нужно:
Рассмотрим ещё один очень похожий случай.
Ошибка N26; MP_MEM превращается в MP_YES
В начале рассмотрим некоторые константы. Они пригодятся нам чуть ниже.
Далее следует сказать, что существует функция mp_init_multi, которая может возвращать значения MP_OKAY и MP_MEM:
И теперь собственно код с ошибкой:
Рассмотрим проверку более тщательно:
Вновь не там поставлена скобка. Поэтому в начале вычисляется:
Значение TEMP может быть только 0 или 1. Этим числам соответствуют константы MB_OKAY и MP_YES.
Далее выполняется присваивание и одновременно проверка:
Видите подвох? Статус ошибки MP_MEM (-2) вдруг превратился в статус MB_YES (1). Последствия предсказать не могу, но ничего хорошего в этом нет.
Ошибка N27; Забыли разыменовать указатель
Предупреждение PVS-Studio: V595 The ‘outbuf’ pointer was utilized before it was verified against nullptr. Check lines: 374, 381. protocomm.c 374
Сообщение анализатора, на первый взгляд, может показаться непонятным. Давайте разбираться.
Если указатель pc->ver является нулевым, то функция досрочно завершает свою работу и при этом записывает значение по адресу, хранящемуся в указателе outbuf:
Запись по этому адресу происходит и далее:
А не нравится анализатору то, что затем этот указатель проверяется:
Действительно, это неправильно, в начале разыменовывать указатель, а только потом его проверять. Ляп в том, что на самом то деле должны были проверять не сам указатель, а то, что в него записали. Здесь просто в проверке опечатались и пропустили оператор разыменования (*).
Ошибка N28; Повторное присваивание
Предупреждение PVS-Studio: V519 The ‘usRegCount’ variable is assigned values twice successively. Perhaps this is a mistake. Check lines: 186, 187. mbfuncholding.c 187
Код явно писался методом Copy-Paste. Строчку скопировали, но изменили только частично. По соседству есть вот такой осмысленный код:
Видимо, и в рассмотренном коде с ошибкой, следовало в первой строке использовать оператор =, а во второй оператор |=.
Логические ошибки
Ошибка N29 — N31; Неправильная работа с кодами возврата (Rare)
Предупреждение PVS-Studio: V547 Expression is always false. linenoise.c 256
Это безобидный вариант неправильной обработки статуса, возвращаемого функцией. Ошибка безобидна в том смысле, что никакой обработки и не предусмотрено. Не получилось записать строчку, так не получилось :). Хотя, как я уже сказал, этот безобидный вариант, такой стиль написания программ явно не является образцом для подражания.
А вот что возвращает эта функция:
The number of objects written successfully, which may be less than count if an error occurs.
If size or count is zero, fwrite returns zero and performs no other action.
Таким образом, проверка статуса является неверной.
Аналогичные места безобидной неправильной проверки статуса:
Ошибка N32, N33; Неправильная работа с кодами возврата (Medium)
Предупреждение PVS-Studio: V547 Expression is always false. linenoise.c 596
Аналогичную ошибку можно найти здесь: V547 Expression is always false. linenoise.c 742.
Ошибка N34; Неправильная работа с кодами возврата (Well Done)
Предупреждение PVS-Studio: V547 Expression is always false. linenoise.c 828
Number of objects read successfully, which may be less than count if an error or end-of-file condition occurs.
If size or count is zero, fread returns zero and performs no other action.
fread does not distinguish between end-of-file and error, and callers must use feof and ferror to determine which occurred.
Этот код ещё более опасный. Ошибка чтения из файла не отлавливается, и программа продолжает работать с данными, случайно имеющимися в этот момент в буфере данных. Т.е. программа всегда считает, что она успешно прочитала из файла очередной байт, хотя это может быть и не так.
Ошибка N35; Использование оператора || там, где нужен оператор &&
Предупреждение PVS-Studio: V547 Expression is always true. essl_sdio.c 209
Эту ошибку можно, конечно, отнести просто к опечаткам, но, мне кажется, по духу она ближе к логическим ошибкам. Думаю, читатель понимает, что деление ошибок по категориям часто является достаточно условным.
Итак, перед нами всегда истинное условие. Ведь некая переменная всегда или больше 0, или меньше 2048. Из-за этого размер какого-то блока не будет ограничен значением 512.
Правильный вариант кода:
Ошибка N35 — N38; Переменная не изменяется
Предупреждение PVS-Studio: V547 Expression ‘depth =), а просто больше (>).
Ошибка N41; Повторное присваивание
Предупреждение PVS-Studio: V519 The ‘* pad_num’ variable is assigned values twice successively. Perhaps this is a mistake. Check lines: 46, 48. touch_sensor_hal.c 48
Код явно ошибочен и возможно здесь не хватает оператора else. Я не уверен, но, возможно, код должен выглядеть так:
Выход за границу массива
Ошибка N42; Неправильная граничная проверка
Предупреждение PVS-Studio: V557 Array overrun is possible. The value of ‘frame->exccause’ index could reach 16. gdbstub_xtensa.c 132
Возможен выход за границу массива на 1 элемент. Для правильной проверки следует использовать не оператор больше, а больше-или-равно:
Ошибка N43; Длинный пример ошибки 🙂
В рассматриваемой функции выход за границу массива может произойти в двух местах, поэтому и предупреждений анализатора сразу два:
Приготовьтесь, это будет сложный случай. Для начала взглянем на следующие именованные константы:
Обратите внимание, что значение константы MDNS_IF_MAX равно 3.
Теперь взглянем на определение структуры mdns_server_s. Здесь нам важно, что массив interfaces состоит из 3 элементов:
Это ещё не всё. Нам понадобится заглянуть внутрь функции _mdns_get_other_if. Обратите внимание, что она может вернуть константу MDNS_IF_MAX. Т.е. она может вернуть значение 3.
И вот, наконец, мы добрались до ошибок:
Итак, мы знаем, что функция _mdns_get_other_if может вернуть тройку. Значит переменная other_if может быть равна трём. И вот первый потенциальный выход за границу массива:
Заглянем в эту функцию:
Опять может использоваться индекс 3 для доступа к массиву, состоящего из 3 элементов. А максимальный доступный индекс — это двойка.
Нулевые указатели
Ошибка N44 — N47; Ошибка очерёдности проверки указателей
Предупреждение PVS-Studio: V595 The ‘hapd->wpa_auth’ pointer was utilized before it was verified against nullptr. Check lines: 106, 113. esp_hostap.c 106
Неправильная последовательность проверки указателей:
Если указатель hapd->wpa_auth окажется нулевым, то всё плохо. Последовательность действий нужно поменять местами и сделать вложенной:
Ошибка N48 — N64; Нет проверки указателя после выделения памяти
В целом, в проекте принято проверять, удалось выделить память или нет. Т.е. много кода с подобными проверками:
Но местами про проверки забыли.
Предупреждение PVS-Studio: V522 There might be dereferencing of a potential null pointer ‘exp’. Check lines: 3470, 3469. argtable3.c 3470
Этот вид ошибки сложнее и опаснее, чем может показаться на первый взгляд. Подробнее эта тема разбирается в статье «Почему важно проверять, что вернула функция malloc».
Другие места, где отсутствуют проверки:
Ошибка N65, N66; Нет проверки указателя после выделения памяти (показательный случай)
Следующий код содержит точно такую же ошибку, как мы рассматривали выше, но она более показательная и яркая. Обратите внимания, что для выделения памяти используется функция realloc.
Предупреждение PVS-Studio: V701 realloc() possible leak: when realloc() fails in allocating memory, original pointer ‘exp->_nodes’ is lost. Consider assigning realloc() to a temporary pointer. argtable3.c 3008
Во-первых, если функция realloc вернёт NULL, то будет потеряно предыдущее значение указателя exp->_nodes. Возникнет утечка памяти.
Во-вторых, если функция realloc вернёт NULL, то запись значения произойдёт вовсе не по нулевому указателю. Имеется в виду эта строка:
Значение exp->_nsize++ может быть любым, и, если запись произойдёт в какую-то случайную область памяти, доступную для записи, то программа продолжит своё выполнение, как ни в чём не бывало. При этом будут разрушены структуры данных, что приведёт к непредсказуемым последствиям.
Ещё одна такая ошибка: V701 realloc() possible leak: when realloc() fails in allocating memory, original pointer ‘m_context->pki_sni_entry_list’ is lost. Consider assigning realloc() to a temporary pointer. coap_mbedtls.c 737
Прочие ошибки
Ошибка N67; Лишний или неверный код
Это странный код, который можно сократить до:
Есть здесь ошибка или нет, мне сказать сложно. Возможно, здесь написано совсем не то, что задумано. А возможно, этот код появился в процессе неудачного рефакторинга и, на самом деле, является корректным. В этом случае его действительно достаточно немного упростить, чтобы он смотрелся красивей и понятней. Одно точно — этот код заслуживает внимания и проверки автором.
Ошибка N68; Лишний или неверный код
В общем-то, всё то же самое, что и в предыдущем случае. Переменная err является лишней или её забыли изменить.
Ошибка N69; Использование потенциально неинициализированного буфера
Предупреждение PVS-Studio: V614 Potentially uninitialized buffer ‘seq’ used. Consider checking the first actual argument of the ‘strlen’ function. linenoise.c 435
Буфер seq может быть заполнен, а может быть и не заполнен! Он заполняется только при выполнении условия:
Логично предположить, что условие может быть не выполнено, и тогда буфер останется неинициализированным. В этом случае его нельзя использовать для добавления к строке ab.
Чтобы исправить ситуацию, стоит изменить код следующим образом:
Ошибка N70; Странная маска
Предупреждение PVS-Studio: V547 Expression is always false. tasks.c 896
Константа portPRIVILEGE_BIT имеет значение 0. Поэтому странно использовать его как маску:
Ошибка N71, Утечка памяти
Предупреждение PVS-Studio: V773 The function was exited without releasing the ‘sm’ pointer. A memory leak is possible. esp_wpa2.c 753
Если функция xSemaphoreCreateRecursiveMutex не сможет создать мьютекс, то функция eap_peer_sm_init завершит свою работу и при этом произойдёт утечка памяти. Как я понимаю, следует добавить вызов функции os_free для очистки памяти:
Что интересно, компилятор Clang тоже предупреждает об этой ошибке. Однако автор кода почему-то проигнорировал и даже специально подавил соответствующее предупреждение:
Наличие этого подавляющего комментария мне непонятно. Ошибка ведь действительно есть. Возможно, автор кода просто не понял, что не нравится компилятору и решил, что это ложное срабатывание.
Заключение
Спасибо за внимание. Как видите, ошибок весьма много. А это ведь был только беглый просмотр неполного отчёта. Надеюсь, Юрий Попов примет эстафету и опишет ещё больше ошибок в своей последующей статье :).
Используйте статический анализатор PVS-Studio регулярно. Это позволит:
Приглашаю скачать и попробовать демонстрационную версию анализатора PVS-Studio. Также напоминаю, что если вы разрабатываете открытый проект или используете анализатор в академических целях, то для таких случаев мы предлагаем несколько вариантов бесплатных лицензий. Не ждите, когда коварный баг съест вашу ногу, начните использовать PVS-Studio прямо сейчас.
Если хотите поделиться этой статьей с англоязычной аудиторией, то прошу использовать ссылку на перевод: Andrey Karpov. Espressif IoT Development Framework: 71 Shots in the Foot.














