18:20 Статический анализ кода |
Стати́ческий ана́лиз ко́да (англ. static code analysis) — анализ программного обеспечения, производимый (в отличие от динамического анализа) без реального выполнения исследуемых программ. В большинстве случаев анализ производится над какой-либо версией исходного кода, хотя иногда анализу подвергается какой-нибудь вид объектного кода, например P-код или код на MSIL. Термин обычно применяют к анализу, производимому специальным программным обеспечением (ПО), тогда как ручной анализ называют «program understanding», «program comprehension» (пониманием или постижением программы). В зависимости от используемого инструмента глубина анализа может варьироваться от определения поведения отдельных операторов до анализа, включающего весь имеющийся исходный код. Способы использования полученной в ходе анализа информации также различны — от выявления мест, возможно содержащих ошибки (утилиты типа Lint), до формальных методов, позволяющих математически доказать какие-либо свойства программы (например, соответствие поведения спецификации). Некоторые люди считают программные метрики и обратное проектирование формами статического анализа. Получение метрик (англ. software quality objectives) и статический анализ часто совмещаются, особенно при создании встраиваемых систем. В последнее время статический анализ всё больше используется в верификации свойств ПО, используемого в компьютерных системах высокой надёжности, особенно критичных для жизни (safety-critical (англ.)русск.). Также применяется для поиска кода, потенциально содержащего уязвимости (иногда это применение называется Static Application Security Testing, SAST). Статический анализ постоянно применяется в следующих областях: ПО для медицинских устройств. ПО для ядерных станций и систем защиты реактора (Reactor Protection Systems). ПО для авиации (в комбинации с динамическим анализом) По данным VDC на 2012 год, примерно 28 % разработчиков встраиваемого ПО применяют средства статического анализа, а 39 % собираются начать их использование в течение 2 лет. Большинство компиляторов (например, GNU C Compiler) выводят на экран «предупреждения» (англ. warnings) — сообщения о том, что код, будучи синтаксически правильным, скорее всего, содержит ошибку. Например: int x; int y = x+2; // Переменная x не инициализирована! Это простейший статический анализ. У компилятора есть много других немаловажных характеристик — в первую очередь скорость работы и качество машинного кода, поэтому компиляторы проверяют код лишь на очевидные ошибки. Статические анализаторы предназначены для более детального исследования кода. Типы ошибок, обнаруживаемых статическими анализаторами Неопределённое поведение — неинициализированные переменные, обращение к NULL-указателям. О простейших случаях сигнализируют и компиляторы. Нарушение алгоритма пользования библиотекой. Например, для каждого fopen нужен fclose. И если файловая переменная теряется раньше, чем файл закрывается, анализатор может сообщить об ошибке. Типичные сценарии, приводящие к недокументированному поведению. Стандартная библиотека языка Си известна большим количеством неудачных технических решений. Некоторые функции, например, gets, в принципе небезопасны. sprintf и strcpy безопасны лишь при определённых условиях. Переполнение буфера — когда компьютерная программа записывает данные за пределами выделенного в памяти буфера. void doSomething(const char* x) { char s[40]; sprintf(s, "[%s]", x); // sprintf в локальный буфер, возможно переполнение .... } Типичные сценарии, мешающие кроссплатформенности. Object *p = getObject(); int pNum = reinterpret_cast<int>(p); // на x86-32 верно, на x64 часть указателя будет потеряна; нужен intptr_t Ошибки в повторяющемся коде. Многие программы исполняют несколько раз одно и то же с разными аргументами. Обычно повторяющиеся фрагменты не пишут с нуля, а размножают и исправляют. dest.x = src.x + dx; dest.y = src.y + dx; // Ошибка, надо dy! Ошибки форматных строк — в функциях наподобие printf могут быть ошибки с несоответствием форматной строки реальному типу параметров. std::wstring s; printf ("s is %s", s); Неизменный параметр, передаваемый в функцию — признак изменившихся требований к программе. Когда-то параметр был задействован, но сейчас он уже не нужен. В таком случае программист может вообще избавиться от этого параметра — и от связанной с ним логики. void doSomething(int n, bool flag) // flag всегда равен true { if (flag) { // какая-то логика } else { // код есть, но не задействован } } doSomething(n, true); ... doSomething(10, true); ... doSomething(x.size(), true); Прочие ошибки — многие функции из стандартных библиотек не имеют побочного эффекта, и вызов их как процедур не имеет смысла. std::string s; ... s.empty(); // код ничего не делает; вероятно, вы хотели s.clear()? |
|
Всего комментариев: 0 | |