Статический и динамический анализ кода: 5 полезных советов

08/10/19
Технические статьи
Статический и динамический анализ кода: 5 полезных советов

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

Более 15 лет Аурига занимается разработкой программного обеспечения для медицинских приборов: от относительно простых глюкометров до более сложных систем — инфузоматов, мониторов пациента, аппаратов искусственной вентиляции легких. Статический и динамический анализ кода является неотъемлемой частью наших процессов. В этой статье мы хотели бы поделиться нашим практическим опытом и находками. 

Статический анализ 

Статический анализ кода – это автоматическая проверка соответствия общепринятым стандартам разработки и оформления кода, таким как MISRA, CERT, AUTOSAR, JSF, а также выявление потенциальных ошибок, например, разыменование нулевого указателя, деление на ноль, переполнение буфера. Современные инструменты статического анализа дополняют практику рецензирования кода, сокращая трудозатраты по меньшей мере на 30%.  

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

Совет 1: Дружите с компилятором 

Дисциплинированные команды разработчиков всегда компилируют код с –Wall и –Werror (в GCC) или /Wall /WX (в Visual Studio), либо используют похожие возможности других компиляторов. Отладка по предупреждениям компилятора – простой и недорогой способ подготовки кода к проведению статического анализа. Мы пришли к выводу, что скрупулезный анализ вывода компилятора способствует сокращению общего объема ошибок, выявленных при статическом анализе. 

Конечно, поправить ошибки по компилятору – это хорошая практика, однако для многих проектов недостаточно и даже неприемлемо использовать для контроля только лишь компилятор. 

После того как все предупреждения компилятора учтены, запустите инструмент статического анализа для более глубокого погружения в код и подробных рекомендаций по улучшению. 

Совет 2: Используйте статический анализ на ранних этапах  

Разрабатывая программное обеспечение для медицинских устройств, необходимо задаться вопросом автоматизации статического анализа кода, поскольку статический анализ является практически обязательным предметом внутреннего/внешнего аудита или предпродажной подготовки.  

Секрет в том, чтобы использовать инструмент статического анализа без снижения скорости разработки, фокусируясь на улучшении качества, а не на борьбе с самим инструментом. Мы достигаем такого баланса за счет практики и опыта, с годами накопленного инженерами Ауриги. Исследуя причины ошибок, обычно мы обнаруживаем, что многие из них легко исправляются. 

Вот несколько примеров по результатам статического анализа, которые могут быть легко исправлены простыми скриптами или при подготовке интернов. 

1)Вызов чистых функций в деструкторах: 

a.Деструктор ‘~CTitle’ не должен вызывать функцию ‘clear_’ в данном случае 

b.Деструктор ‘~THelper’ не должен вызывать функцию ‘removeModule’ в данном случае  

2)Проверка на NULL: 

a.’pMP’ может быть null 

b.'((NPage*)this)->pSysCfg_’ может быть null 

3)Объявление в неправильном месте: 

a.Член ‘D_FILE_1’ объявлен как ‘public’ 

4)Неконстантные аргументы: 

a.Строковый литерал «MCollection» передается в функцию ‘FixedBlockHeap’ как указатель на неконстантный объект 

Многие недочеты в текущем коде можно отложить и вернуться к ним, когда появится время. Однако, важно не привносить дополнительные ошибки (технический долг) во время разработки кода. Инструмент Parasoft C/C++ test позволяет инженерам фильтровать помехи и сосредотачиваться на решении наиболее важных ошибок, найденных в ходе статического анализа. 

Динамический анализ 

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

Совет 3: Относитесь гибче к среде выполнения  

Понятие «встроенный» относится ко многим устройствам: от 8-битных микроконтроллеров с килобайтами оперативной и флеш-памяти до 64-битных многоядерных процессоров с гигабайтами оперативной памяти и высокоскоростными твердотельными накопителями. Если для ежедневной работы достаточно минимальных ресурсов памяти и вычислительной мощности, производители выбирают оборудование, исходя из потребностей, с учетом размера, загрузки и финансовых ограничений. Принято иметь некоторый запас мощности для сопровождения и обновления программных средств, однако этого может быть недостаточно для инструмента динамического анализа, поскольку данный процесс требует огромного количества оперативной памяти (по сравнению с работой в штатном режиме) и дискового пространства для сбора результатов покрытия кода тестами. 

Когда объем памяти на устройстве недостаточен, операционная система может быть непригодна для сбора информации о покрытии кода, а также для модульных и интеграционных тестов. Если ваша операционная система не имеет встроенной поддержки, ищите альтернативу. Возможно, существует родственная операционная система с большим количеством интерфейсов и объемом памяти, поддерживаемая инструментом динамического анализа. Ее вы и можете использовать для модульных и интеграционных тестов. Также можно использовать эмуляторы процессов ARM Fast Models и QEMU. 

Несмотря на то, что наиболее предпочтительным является проведение тестирования на целевой операционной системе, модульные и интеграционные тесты для некоторых приложений часто выполняются на машине разработчика (Linux, Mac, Windows). Это делается для ускорения цикла разработки и из-за большего количества инструментов, доступных для операционных систем общего назначения. В таком случае необходимо переносить встроенный код для сборки основным компилятором, что может вызывать сложности. 

Существует множество компиляторов, систем сборки кода, платформ и способов взаимодействия с ними. Инструменты динамического анализа поддерживают общие принципы построения программ, основываясь на внутренней интерпретации инструкций разработчика. Поэтому даже если код является переносимым, вероятнее всего, разработчикам потребуется дополнительное время на приведение настроек инструмента динамического анализа в соответствие с системой сборки кода в проекте. 

Рекомендуется заранее оценить весь объем работ, чтобы выбрать наиболее оптимальный подход к разработке и поддержке в долгосрочной перспективе. 

Совет 4: Не полагайтесь на автоматически сгенерированные тестовые сценарии 

Для увеличения покрытия кода современные инструменты динамического анализа автоматически генерируют наборы модульных тестов. Однако инструменты не предусматривают различные сценарии использования готовой программы, особенно при попытках увеличения покрытия кода, когда размываются границы между чистыми модульными и интеграционными тестами. Приходится вручную обновлять сгенерированные модульные тесты и даже писать новые, потому что только разработчику известно, как должен работать код, когда речь идет о позитивных или негативных результатах тестов. 

По нашему опыту на наборе файлов в контрольном участке покрытие кода автоматически сгенерированными модульными тестами было от 40% до 100% в каждом файле. Однако в среднем по проекту показатели могут варьироваться от 25% до 60%.  

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

Совет 5: Не стоит недооценивать квалификацию и валидацию инструментов разработки  

Требования некоторых регулирующих органов включают сертификацию и квалификацию инструментов разработки для подтверждения ожидаемого поведения и результатов, в большинстве случаев по протоколу тестирования IUV (Intended Use Validation). 

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

Выводы 

Проверяйте правильность выбора инструмента для каждой конкретной задачи. 

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

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

Создавайте платформенно-независимый код. Даже если не планируете сейчас переносить свой код на другую платформу, это может понадобиться в будущем. Также этот подход поможет сохранить код ясным, легким в сопровождении, удобочитаемым, что всегда важно для рецензирования и будущей поддержки. 

Не полагайтесь всецело на автоматически сгенерированные тестовые сценарии. Это поможет улучшить качество кода. 

Если вам нужна помощь в проведении статического и динамического анализа, пожалуйста, свяжитесь с нами.

Свяжитесь с нами напрямую

Офисы

Москва

117587, Варшавское ш., д. 125, стр. 16А

Ростов-на-Дону

344002, пр. Буденновский, д. 9, офис 305

Нижний Новгород

603104, ул. Нартова, д. 6, корп. 6, офис 829