Вычислительные машины и программное обеспечение
УДК 004.42.05
М.Ю. Моисеев, A.B. Карпенко
РАСЧЕТ МЕТРИК НАДЕЖНОСТИ ПРОГРАММ НА ОСНОВЕ СТАТИЧЕСКОГО АНАЛИЗА
Сегодня все большее внимание уделяется вопросам обеспечения заданного уровня надежности программного обеспечения (ПО). В первую очередь это касается ПО, которое применяется в составе технических систем с повышенными требованиями к надежности и безопасности (системы управления транспортными средствами, медицинские системы, системы военного назначения и др.).
Основная причина недостаточной надежности ПО — ошибки разработчиков на разных стадиях жизненного цикла. Наибольшее количество ошибок вносится на стадии кодирования, будем называть их программными дефектами. Для срабатывания дефекта. имеющегося в программе, необходимо возникновение определенных условий. В случае, если сработавший дефект оказывает влияние на результаты работы программы, говорят о проявлении дефекта: выдача некорректных результатов, зависание или аварийное завершение программы и др.
В основе большинства методов повышения надежности ПО лежит обнаружение и исправление программных дефектов. Используя те или иные методы повышения надежности ПО. необходимо контролировать получаемый результат, для этого применяются оценки надежности ПО. Эти оценки позволяют наблюдать за процессом роста надежности, анализировать эффективность используемых подходов, прогнозировать ресурсы, требуемые для достижения заданного уровня надежности. Измерение надежности ПО является актуальной задачей, которую необходимо ре-
шать при промышленной разработке программного обеспечения [1].
Наиболее естественным подходом к оценке надежности ПО видится измерение показателей надежности, достижение которых задано в спецификации. Обычно в качестве таких показателей используют среднее время безотказной работы, коэффициент готовности и вероятность или интенсивность отказов, будем называть эти показатели абсолютными оценками надежности. Чтобы их получить, применяют динамические методы — методы анализа, основанные на выполнении программы. Получение абсолютных оценок с достаточной степенью достоверности представляется сложной и ресурсоемкой задачей, решение которой не может быть полностью автоматизировано. При использовании динамических методов обнаружение дефектов возможно только в случае их проявления, что негативно влияет на точность таких оценок. Еше один недостаток оценок надежности, полученных динамическими методами, — зависимость от условий, в которых проводились запуски программы — в других условиях полученные оценки могут оказаться неверными. Необходимость компиляции и выполнения программы сужает область применения этих методов. Примерами динамических методов оценки надежности являются методы, основанные на использовании модели Шумана, модели Джелинского — Мо-ранды или модели Муссы \2\.
Другим способом оценки надежности ПО является использование методов,
основанных на статическом анализе (СА) исходного кода. Применение статического анализа позволяет получать оценки, характеризующие программу с точки зрения наличия дефектов. Такие оценки верны для самой программы и не зависят от условий ее выполнения, что одновременно является как преимуществом, так и недостатком. На основе этих оценок не могут быть рассчитаны абсолютные оценки надежности. Причина кроется в невозможности в общем случае расчета вероятности проявления дефекта при его срабатывании, а также в отсутствии учета конкретных условий эксплуатации программы при формировании оценок.
Существует ряд подходов, позволяющих получать оценки надежности программ на основе анализа исходного кода, например использование моделей сложности программы. В основе идеи использования моделей сложности лежит взаимосвязь между сложностью и надежностью программного обеспечения. Примерами таких моделей являются модель Холстеда, оценка циклома-тической сложности Мак-Кейба, метрики Чепина [3]. Модели сложности обладают следующими недостатками: не используется семантическая информация, содержащаяся в исходном коде программы, не учитываются взаимосвязи между отдельными частями программы, не анализируются возможные пути выполнения программы, не учитываются исправленные дефекты.
В данной статье предлагаются метрики надежности исходного кода программ и рассматриваются способы их применения для оценки надежности ПО. Метрики надежности рассчитываются с помощью статического анализа одновременно с обнаружением дефектов. Предлагаемый подход применим для различных языков программирования, в качестве примера используется язык С. В статье развиваются и обобщаются идеи, изложенные в работе [4], в частности обеспечивается более точный анализ операторов ветвления и циклов.
Метрики надежности
Рассмотрим программу, имеющую дефект в некоторой конструкции. Срабатывание этого дефекта при выполнении про-
граммы зависит от состояния программы в данной конструкции. Под состоянием программы будем понимать совокупность состояний всех ее внутренних объектов. Определим вероятность срабатывания дефекта в конструкции программы как сумму вероятностей состояний программы, в которых этот дефект сработает.
Будем использовать алгоритмы статического анализа, результаты которых являются полными — содержат все возможные состояния программы, но не являются точными — могут содержать нереализуемые состояния. Нереализуемые состояния программы — те, которые не могут быть достигнуты ни на одном из возможных путей ее выполнения. Будем называть возможные пути выполнения программы альтернативными путями. Определим точность алгоритмов СА в конструкции программы как долю реализуемых состояний программы среди всех состояний, определенных алгоритмами статического анализа. На рис. I представлены результаты работы алгоритма СА. Если предположить, что все возможные состояния программы равновероятны, то вероятность срабатывания дефекта
равна Точность алгоритмов СА рав-
И
Ici
Множество
программы, приводящие к срабатыванию дефекта
Рис. 1. Результаты статического анализа программы
Обозначим метрику, характеризующую вероятность срабатывания дефекта в /-й конструкции программы, как к,, метрику, характеризующую точность анализа. — 0Л В данной статье рассматриваются вопросы формирования и использования метрик У?/ и /),.
Статический анализ. Рассмотрим основные стадии алгоритма СА для обнаружения дефектов в исходном коде программы. На первой стадии формируется модель программы, удобная для проведения дальнейшего анализа. На второй стадии производится извлечение информации, необходимой для обнаружения дефектов. Полученная информация представляет собой состояния различных объектов программы — переменных, указателей на объекты, указателей на функции и др. Состояние объектов программы описывается с помощью кортежей. Каждый кортеж связывает объект программы с его состоянием. Набор кортежей для всех объектов программы определяет ее состояние. При проведении потоково-чув-ствительного анализа состояния программы в отдельных конструкциях рассматриваются раздельно. Обозначим состояние программы на входе и выходе /-й конструкции и Я'"" соответственно. На последней стадии алгоритма С А проверяется выполнение условий срабатывания дефектов на основе полученного набора кортежей. Необходимо отметить, что для одного и того же объекта может быть несколько кортежей в одной конструкции программы.
Оценки вероятностей кортежей
Основой для расчета метрик /?, и Э, выступают оценки вероятности существования кортежей. Для формирования этих оценок необходимо расширить правила алгоритмов анализа, извлекающих информацию для обнаружения дефектов. В качестве примера будем использовать алгоритм анализа указателей.
Алгоритм анализа указателей определяет объекты, на которые могут указывать пе-ременные-указатели в конструкциях программы. Эта информация представляется в виде кортежей (р, о, г), состоящих из пере-
менной-указателя р, объекта, на который он может указывать о, и оценки вероятности г.
Исходными данными для алгоритма анализа указателей является модель программы. В качестве модели программы выбрано SSA-представление (Static Single Assignment, статическое однократное присваивание) [5]. Одна из особенностей SSA — использование в местах соединения альтернативных путей выполнения программы специальных конструкций — ф-функций, которые обеспечивают объединение кортежей, полученных на альтернативных путях.
Алгоритм анализа указателей строит уравнения для конструкций программы, которые могут повлиять на значения указателей. Такими конструкциями в языке С являются библиотечные функции выделения и освобождения памяти, операции взятия адреса, разыменования и присваивания указателей, арифметические операции над указателями, операторы ветвления и ф-функции. Неизвестными в этих уравнениях являются множества кортежей. Составленные уравнения объединяются в систему уравнений, которая решается с использованием теории решеток\Ь]. Расчет оценок вероятности кортежей осуществляется в процессе решения системы уравнений.
Для того чтобы оценки вероятности, полученные на разных путях, были сравнимы между собой и находились в диапазоне от нуля до единицы, необходимо, чтобы для каждой конструкции программы сумма оценок вероятностей кортежей на выходе конструкции была равна сумме оценок вероятностей на ее входе. Будем называть это ограничение условием нормировки.
Правила оценки вероятности кортежей для основных конструкций. Рассмотрим правила формирования уравнений алгоритма анализа указателей для различных конструкций языка С.
Объявление переменной-указателя приводит к добавлению кортежа с оценкой вероятности, равной вероятности выполнения данной конструкции программы /?/""'. Расчет значения R"m приведен ниже. При выходе переменной из области видимости все кортежи для этой переменной удаляются.
При выделении объекта в динамической памяти вероятность нового кортежа равна сумме вероятностей всех кортежей для этого указателя на входе конструкции:
[р = ma/loci)], : S"'" = = Si"u(p,o,R;)/ (J (р,о,г),
где о — объект, созданный функцией mallocQ; R"' = ^г — суммарная веро-
ятность всех кортежей для указателя р на входе конструкции.
При освобождении объекта через указатель р удаляются все имеющиеся кортежи для р и добавляется кортеж с р в левой части и некорректным объектом (неинициализированный объект, освобожденный объект, NULL) в правой. Необходимо также учитывать другие указатели, которые могли указывать на освобожденный объект, — для таких указателей добавляются кортежи с некорректным объектом в правой части. Для функции freei) используется правило
[free{p)\:Sr=Sr<j(p,oinmlid,R;):
V(p,o.r)eS;"
^ U q,omvalid,
V(p.orr,| ),(<j.orrl2 )eS,'" V
R
p /
где о!т,аЫ — некорректный объект. Для выполнения условия нормировки необходимо скорректировать значение вероятностей:
гп'гп
где — результирующее значение вероятности.
Пример работы этих правил приведен на рис. 2.
Правила для операции взятия адреса и разыменования указателя следующие:
: ^(р.о.г);
[р = *д\ : 5/"" = 5/" и
^ и (Р'°к>-п
•'л -Гц
/Г • R"
)/ |J(p,o,r).
v(r.o.r)£.\;"
42 11
r:
■y(p,Oj,rn),(q,Oj,rn)e S"
Расчет оценок вероятности для других конструкций выполняется аналогичным образом.
Правила оценки вероятности кортежей для конструкций потока управления. Будем называть конструкциями потока управления ф-функции и операторы ветвления. В ф-функ-циях одинаковые кортежи, полученные со всех входящих путей, объединяются в один кортеж, вероятности исходных кортежей суммируются.
При разделении путей выполнения программы в операторах ветвления необходимо рассчитывать вероятности перехода по каждой выходной дуге. Будем называть условие оператора ветвления интерпретируемым., если оно может быть вычислено с помощью статического анализа. Примерами интерпретируемых условий являются сравнение указателя с NULL, сравнение указателя с другим указателем, комбинации
ч
Р г*
ч 1
г»'"
R., = г3 + г4
Рис. 2. Правило для конструкции free(p)
этих условий с использованием логических операторов.
Рассмотрим интерпретируемое условие cond = LF(P), Р = ..., рт, где LF — некоторая функция, р, — переменные-указатели. Будем считать, что значение функции LFдля любого набора кортежей CS„ в точности равно true или false. Каждый набор CSn включает в себя ровно по одному кортежу для каждой переменной из Р. Обозначим вероятности перехода для выходных дуг оператора ветвления Rtrue и Rfalse.
Выполним расчет вероятности перехода R,me для условия cond = LF(P)\
X П'
VCS„ :LF{CS„ )~lrue V( p.и.r )e CS„
Вероятность Rfalse рассчитывается аналогичным образом. Для обеспечения условия нормировки, значения Rtme и Rfatse корректируются так, чтобы их сумма стала равна единице. После расчета вероятности переходов формируется два множества кортежей, удовлетворяющих условию cond и —cond, для дуги tine и дуги false соответственно. Для кортежей (р, о, /•), таких, что р € Р. расчет вероятностей на выходных дугах выполняется следующим образом:
r[(p,o,r)X"'ue = г ■ R,rue, r[(p,o,r)fftL = г' Rfrlse-
Для кортежей (р. о, г), таких, что р е Л необходимо рассчитывать индивидуальные коэффициенты нормировки R\(p, о, г)],те и /?[(/>, о, r)\fahe. Вероятность того, что для всех CS„, в которые входит кортеж (р, о, г), условие cond выполнится, равна:
*k/w)L= I П'- •
VC5„:(/>.<>. г )е CS„. V( р.о.г х= С5„
LF(CS„ )=гте
Полученные значения R[(p, о, г)],гие и /?[(р. о, г)]raise корректируются так, чтобы их сумма стала равна единице. Расчет вероятности кортежа (р, о, г) на выходных дугах выполняется следующим образом:
r[(p,o,r)^'ie =r-R[(p,o,r) ]i/w,
r[(p,o,r)Yl"be = г ■ R[(p,o,r)]/alse.
Для неинтерпретируемых условий выполняется аналогичная процедура с учетом
того, что переходы считаются равновероятными.
Для расчета вероятности выполнения 1-й конструкции программы /?/""' необходимо добавить искусственный кортеж для переменной (не входящей в условия операторов ветвления) с г = 1 в первую конструкцию программы. Значение /?/'"" равно вероятности этого кортежа в /-й конструкции программы.
Правила расчета вероятности кортежей для оператора ветвления и ф-функции показаны на рис. 3. Рис. 4 содержит пример анализа программы, иллюстрирующий применение предложенных правил; на дугах даны вероятности переходов; будем считать, что oimaiid во входных кортежах эквивалентен значению указателя, равному NULL.
Правила оценки вероятности кортежей для циклов. Рассмотренные выше правила расчета оценок вероятности в конструкциях потока управления обеспечивают выполнение условия нормировки при отсутствии циклов. Для анализа программ, содержащих циклы, необходимо дополнить эти правила. Обнаружение циклов и определение входов и выходов для каждого цикла выполняется на этапе формирования модели программы с помощью известных алгоритмов [7].
Рассмотрим цикл с одним входом и одним выходом. Его можно представить в виде необходимого числа копий тела цикла, как это сделано на рис. 5. Входом в цикл служит ф-функция. выходом — оператор ветвления.
• • • • • •
г — г Л- г
у
Рис. 3. Правила для конструкций потока управления
' Ч • °1т Ын/' 1)
'С/' > 3 )
(Р'°ипа1 И> |2)
(р, о, , (р, о}, \){р, о,таЫ, /
(р,о1,(р,оъ,£)(/?,о1таЫ,
Рис. 4. Пример анализа программы
При расчете вероятностей кортежей внутри цикла в процессе решения системы уравнений алгоритма анализа указателей для входной ф-функции используют следующие правила:
все кортежи, пришедшие по входной дуге цикла, передаются на выход ф-функ-ции без изменений;
кортеж, пришедший по внутренней дуге цикла, передается на выход ф-функции, только если в ф-функции до сих пор не было такого кортежа (в обычных ф-функциях вероятности одинаковых кортежей суммируются).
Решение уравнений для конс трукций, входящих в цикл, выполняется до тех пор, пока
появляются новые кортежи. В процессе решения необходимо отличать кортежи, полученные на текущей итерации анализа цикла, для расчета кортежей следующих итераций.
Предложенный подход обеспечивает выполнение условий нормировки для цикла в целом: вероятность любого кортежа внутри цикла не превышает суммарную вероятность кортежей для этой переменной на входе цикла, и суммарная вероятность кортежей для любой переменной на выходе цикла в точности равна суммарной вероятности кортежей на входе этого цикла. Последнее условие выполняется за счет условия нормировки в операторах ветвления.
Входная дуга цикла
г
Ф К
Внутренняя дуга цикла
1 г
г
Б2
1 Г >
(1-Я)-/
1 г
Б2
1 г
1 / / Г г
Яг
1 г
Б2
1
Рис. 5. Правила для конструкций потока управления в циклах
Предложенная модель цикла позволяет получить результат, максимально приближенный к результату для развернутого цикла.
Рассмотрим расчет вероятностей кортежей для других видов циклов. Для циклов с несколькими выходами расчет вероятностей кортежей выполняется аналогично. Расчет вероятностей кортежей для циклов с несколькими входами требует предварительной модификации модели программы: цикл с N входами заменяется на N циклов с одним входом каждый. В цикле с несколькими входами удаляются все входные ср-функции, кроме одной. Для каждой удаленной (р-функции создается копия тела цикла, в которой существует вход только через эту ср-функцию. В случае, если в исходном цикле было несколько выходов, соответствующие выходы всех копий цикла объединяются по отдельности в специально добавленных (р-функци-ях. Пример модификации модели программы представлен на рис. 6. В правой части
рисунка представлена модель с двумя копиями исходного цикла — удаленные ср-функ-ции отмечены штриховкой.
Расчет метрик надежности
С помощью правил обнаружения дефектов можно определить кортежи, для которых выполняются условия срабатывания дефекта. Расчет метрики /?, производится по формуле
= Хг
где ОЕГ, — множество кортежей, которые приводят к срабатыванию дефекта в 1-й конструкции программы. Например, дефект, связанный с разыменованием указателя р на некорректный объект, срабатывает для всех кортежей с этим указателем и некорректным объектом. Вероятность срабатывания данного дефекта определяется как сумма оценок вероятности всех таких кортежей.
Рис. 6. Пример раскрытия цикла с несколькими входами
Расчет метрики /), основан на предположении. что точность анализа и неопределенность состояний программы взаимосвязаны. Пусть в /-Й конструкции программы происходит срабатывание дефекта, связанного с указателем р. Будем называть группой событий Х1Г все возможные кортежи для в этой конструкции. Вероятности событий в Х*р нормируются к единице, чтобы полученные значения были сравнимы между собой. В качестве меры неопределенности используется энтропия
Х*р. Н(х'р)=- Хг1оё2г. Значения Н(Х<р)
будут неотрицательными, = 0 в слу-
чае отсутствия неопределенности: Н(Х'р) возрастает с ростом неопределенности. Метрика характеризующая точность анализа, рассчитывается следующим образом:
где С — нормирующий множитель. £>, находится в диапазоне от нуля до единицы, где значение 1 соответствует абсолютно точному анализу, значение 0, достижимое в пределе, — неточному.
Использование предложенных метрик
Полученные метрики могут использоваться для принятия решения об обнаружении дефекта. Для этого значения Я/ сравниваются с некоторым порогом П, при превышении которого дефект считается обнаруженным. Значение порога П находится в диапазоне от нуля до единицы. При нулевом значении П будут выдаваться сообщения обо всех потенциальных дефектах, некоторые из этих сообщений могут оказаться ложными. При увеличении порога число ложных предупреждений снижается, при этом часть истинных дефектов может быть не обнаружена. При значении П. равном единице, будут выдаваться сообщения только о дефектах, которые проявляются во всех состояниях программы в соответствующих конструкциях. При использовании такого подхода можно считать, что все обнаруженные дефекты проанализированы и при необходимости исправлены. Количество оставшихся в программе дефектов /V, рассчитывается так:
'' ПЕГ
где { , Л/)<гг — число всех
[у(/?/) = 0./?/ >П
дефектов.
Полученная оценка количества дефектов N отражает рост надежности при отладке программы и может использоваться для управления этим процессом. На основе значения N может оцениваться среднее количество ошибок на тысячу строк программы, применяемое для определения наиболее уязвимых ее частей, а также для сравнения разных программ.
На основе метрики £>, можно сформировать оценку точности анализа програм-
N....
£а
мы £> = -^7-. Полученная оценка /Эхарак-
теризует долю ложных дефектов среди всех дефектов. Эта оценка может использоваться при настройке параметров алгоритмов СА для обеспечения требуемой точности анализа.
Состоятельность предложенных оценок N и И может быть доказана с помощью постановки экспериментов на реальных программных системах. Для этого планируется реализовать расчет метрик надежности и формирование этих оценок в составе системы автоматического обнаружения дефектов, разрабатываемой в настоящее время на кафедре автоматики и вычислительной техники СПбГПУ.
Итак, в статье предложены метрики надежности ПО. формируемые на основе ста-
тического анализа исходного кода программы. Метрика Я, характеризует вероятность срабатывания дефекта в 1-й конструкции программы, метрика £), — точность проведенного анализа. Расчет этих метрик выполняется в процессе обнаружения дефектов.
Предлагаемые метрики могут использоваться разработчиками ПО для решения следующих задач: отслеживания динамики роста надежности ПО; поиска наиболее уязвимых частей программы; сравнения надежности разных программ; настройки алгоритмов статического анализа. для обеспечения требуемой точности результатов.
Недостатком предложенного подхода является взаимная зависимость Я/ и /)/, которая может понизить эффективность применения обеих метрик. Эта зависимость связана с тем, что Я, и й, формируются на основе оценок вероятности кортежей, которые одновременно учитывают два вида неопределенностей: входных данных программы; неточностей алгоритмов СА. Для устранения этого недостатка необходимо формировать оценки кортежей, учитывающие неопределенности каждого вида по отдельности.
Исследование выполнено в рамках работ по государственному контракту № 02.514.11.4081 "Исследование и разработка системы автоматического обнаружения дефектов в исходном коде программного обеспечения" Федерального агентства по науке и инновациям.
СПИСОК ЛИТЕРАТУРЫ
1. Guide to the software engineering body of knowledge / IEEE Computer Society, (http:// www.swebok.org).
2. Lyu VI.R. Handbook of software reliability engineering //IEEE Computer Society Press. 19%. 850 p.
3. Kan S.H. Metrics and Models in Software Quality Engineering. Addison-Wesley, 2002. 512 p.
4. Ииыксон B.M., Моисеев М.Ю., Цесько B.A., Захаров А.В., Ахин М.Х. Алгоритм интервального анализа для обнаружения дефектов в исходном коде программ // Информационно-управляющие системы. 2009. № 2.
5. Cytron R. et al. Efficiently Computing Static Single Assignment Form and the Control Dependence Graph // ACM Transactions on Programming Languages and Systems (ACM New York). 1991. Vol. 13. № 4. P. 451-490.
6. Nielsen F., Nielson H.R., Hankin C. Principles of Program Analysis. Berlin: Springer. 2005. 452 p.
7. Касьянов В.H., Евстигнеев В.А. Графы в программировании. СПб.: БХВ-Петербург, 2003. 1104 с.