Научная статья на тему 'Формализация определения ошибок при статическом символьном выполнении'

Формализация определения ошибок при статическом символьном выполнении Текст научной статьи по специальности «Компьютерные и информационные науки»

CC BY
240
42
i Надоели баннеры? Вы всегда можете отключить рекламу.
Ключевые слова
СТАТИЧЕСКИЙ АНАЛИЗ / ОПРЕДЕЛЕНИЕ ОШИБОЧНОЙ СИТУАЦИИ / СИМВОЛЬНОЕ ВЫПОЛНЕНИЕ / STATIC ANALYSIS / ERROR CRITERIA / SYMBOLIC EXECUTION

Аннотация научной статьи по компьютерным и информационным наукам, автор научной работы — Кошелев В.К.

Данная работа посвящена формализации понятия ошибочной ситуации при статическом анализе исходного кода, основанном на символьном выполнении. При использовании методов символьного выполнения для статического анализа необходимо пересматривать критерий выдачи ошибок, так как оригинальный критерий приводит к чрезмерному числу ложных срабатываний. Для решения этой проблемы предлагаются альтернативные определения ошибочной ситуации, сообщающие об ошибке только в том случае, когда она происходит на некотором множестве значений входных переменных. Примерами таких множеств являются, например, множество значений входных переменных, при которых управление пройдет через заданную точку программы, или множество значений, при которых управление пройдет по заданному пути в графе потока управления. В данной работе рассматриваются различные способы задания таких множеств начальных значений. Анализируются полученные таким образом определения ошибочных ситуаций. Приводятся алгоритмы, обнаруживающие данные ошибочные ситуации, а также доказывается их соответствие. Рассматривается практическое применение приведённых определений ошибочных ситуаций, а именно: классификация срабатываний инструментов статического анализа; учет неизвестных контракта вызова анализируемой функции; использование определения ошибочной ситуации в качестве запроса к SMT-решателю для поиска точного решения в соответствии с данными определением.

i Надоели баннеры? Вы всегда можете отключить рекламу.
iНе можете найти то, что вам нужно? Попробуйте сервис подбора литературы.
i Надоели баннеры? Вы всегда можете отключить рекламу.

Formalization of Error Criteria for static symbolic execution

This paper is devoted to the formalization of the error criteria for program static analysis, based on symbolic execution. Using the original error criteria of symbolic execution approach in program static analysis leads to an excessive number of false positives. To solve this problem, we propose an alternative definition of the error criteria. Proposed definition reports errors only if they occur on a certain set of input variables. Examples of such sets are the set of values ​​of input variables in which control will pass through a given point of the program, or set of values ​​in which the controls take place along a given path in the control flow graph. This paper discusses the various ways to specify such sets of initial values, including analysis of the final error criteria. We overview algorithms corresponding to the error criteria and prove their correctness. Finally, we consider the practical applications of the given error criteria, which include classification of the warnings generated by static analysis tools; taking into account unknown function contracting, especially preconditions; using the proposed error criteria as formulas for a SMT-solver. The latest application allows to get the precise solution of the particular error criteria, including the error trace.

Текст научной работы на тему «Формализация определения ошибок при статическом символьном выполнении»

Формализация определения ошибок при статическом символьном выполнении

В.К. Кошелев <vedun@ispras.ru> Институт системного программирования РАН, 109004, Россия, г. Москва, ул. А. Солженицына, д. 25

Аннотация. Данная работа посвящена формализации понятия ошибочной ситуации при статическом анализе исходного кода, основанном на символьном выполнении. При использовании методов символьного выполнения для статического анализа необходимо пересматривать критерий выдачи ошибок, так как оригинальный критерий приводит к чрезмерному числу ложных срабатываний. Для решения этой проблемы предлагаются альтернативные определения ошибочной ситуации, сообщающие об ошибке только в том случае, когда она происходит на некотором множестве значений входных переменных. Примерами таких множеств являются, например, множество значений входных переменных, при которых управление пройдет через заданную точку программы, или множество значений, при которых управление пройдет по заданному пути в графе потока управления. В данной работе рассматриваются различные способы задания таких множеств начальных значений. Анализируются полученные таким образом определения ошибочных ситуаций. Приводятся алгоритмы, обнаруживающие данные ошибочные ситуации, а также доказывается их соответствие. Рассматривается практическое применение приведённых определений ошибочных ситуаций, а именно: классификация срабатываний инструментов статического анализа; учет неизвестных контракта вызова анализируемой функции; использование определения ошибочной ситуации в качестве запроса к 8МТ-решателю для поиска точного решения в соответствии с данными определением.

Ключевые слова: статический анализ; определение ошибочной ситуации; символьное выполнение.

Б01: 10.15514/18РКА8-2016-28(5)-6

Для цитирования: Кошелев В.К. Формализация определения ошибок при статическом символьном выполнении. Труды ИСП РАН, том 28, вып. 5, 2016, стр. 105-118. БОР 10.15514/18РКА8-2016-28(5)-6

1. Введение

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

105

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

Один из сценариев использования статического анализатора предполагает регулярный анализ проектов во время разработки. Для исполнения этого сценария к статическому анализу предъявляется ряд требований. Во-первых, статический анализатор должен быть способен проводить анализ функции, не имея информации о точках её вызова. Это необходимо как для анализа ещё недописанного кода, так и для анализа библиотек. Во-вторых, при определении понятия ошибочной ситуации анализ должен учитывать наличие в коде вызовов неизвестных функций.

К сожалению, в существующих работах по статическому анализу [1] [2] [3], авторы акцентируют внимание на построении анализа, оставляя за скобками определение ошибочной ситуации. Целью данной работы является разработка формальных определений ошибочных ситуаций, позволяющих выдавать предупреждения с различной степенью уверенности относительно неизвестных значений.

Один из вариантов определения ошибочной ситуации, учитывающей контексты вызова и внешние функции, был рассмотрен в работе [4], посвящённой поиску внутрипроцедурной ошибки переполнения буфера. Данная работа формализует и расширяет определение ошибочной ситуации, использующееся в работе [4] для произвольных детекторов ошибок, основанных на методе символьного выполнения. Рассматриваются примеры реальных детекторов ошибок в программах на языке С#, включая доказательство соответствия с данными определениями ошибочных ситуации.

2. Статический анализ с помощью символьного выполнения

Символьное выполнение [5] широко используется для автоматической генерации тестов. В этом случае выполнение начинается с точки входа

программы, а входные данные программы считаются символьными. От символьного выполнения требуется подобрать входные данные, на которых произойдет ошибка. Пусть е - шаг символьного выполнения, Ре - предикат пути для шага е, а Егге - условие возникновения ошибки на шаге е, тогда наличие ошибки на шаге е задается следующей формулой:

(1) Эх : Ре (s) A Erre (s), s - вектор символьных переменных

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

Отсутствие этой необходимости позволяет рассматривать каждую функцию, представленную в программе, в качестве точки входа. В этом случае аргументы анализируемой функции и состояние памяти в момент её вызова параметризируются набором символьных переменных. Данный подход используется в ряде работ, включая [1], [2], [3]. Однако, в этом случае условие наличие ошибки (1) не может быть использовано ввиду чрезмерного количества ложных срабатываний. Рассмотрим следующий пример.

1) public class A {

2) public int X;

3) public static int Foo(A a, bool five) {

4) if (five)

5) return a.X;

6) else

7) return 5;

8) } 9) }

Напишем условие ошибки NullReferenceException для точки (5).

За,five ■ five А а = null Данная формула имеет решение а = null,five = true, однако функция Foo может иметь неявные предусловия, запрещающее переменной а иметь значение null. На практике, использование условия ошибки (1) для поиска NullReferenceException приведет к обнаружению ошибки практически в каждой функции.

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

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

Предполагается, что анализ проводится над некоторым набором путей выполнения. Множество таких путей удобно описывать при помощи графа развертки. Ациклический ориентированный связанный граф с выделенными истоком и стоком G' = (V', Е',v'entry,v'exit), будем называть графом развертки для ГПУ G = (7, Е, ventry, vexit), если найдется функция соответствия ip : V' -* V, такая что выполнено:

(2) ip(ventry) = ventry ip(vexit) = vexit

(3) (v',u') 6 E' -> <VO'), V("')> e E

(4) (v',u') E E' A {v',w') Ef'Aii'iw' -> V(u') * V'(W)

Графом развертки, например, является дерево выполнений программы, проходящих по обратным рёбрам не более k-раз. Так как размер такого дерева экспоненциально зависит от размера исходной программы, на практике используются ациклические графы. Пример алгоритма построения ациклического графа развертки приведен в работе [6].

Будем говорить, что путь I = (v0 = ventry,v1,v2, ■■■ ,vn) от истока на ГПУ принадлежит к графу развертки G' (обозначим как1/)(0 6 G'), если найдется такой путь Г = {v'0 = v'entry,v'ítv'2, ...,v'n) в G', что Víe[0jn]VOD = vi■ Заметим, что исходя из свойства (4), если путь I' существует, то он единственный. Тогда символьное выполнение должно производить поиск ошибок среди путей I 6 G, таких, что */>(/) 6 G'. Учитывая введённую параметризацию, ход выполнения в рассматриваемой модели полностью определяется значением символьных переменных.

3. Определения ошибочных ситуаций

Пусть I - множество значений вектора символьных переменных s. Тогда рассмотрим множество {I¿} Е 2е, где I¿ Е I. Элемент I¿ назовём абстракцией, a {IJ — множеством абстракций. Будем говорить, что в программе в точке В содержится ошибка, если найдется такая абстракция Z¿, что на всех наборах значений переменных a 6 Z¡ произойдет ошибка в точке В. 2. _

Обозначим как Рв 1 (s) формулу от символьных переменных, задающую условие того, что s принадлежит абстракции I¿ и управление дойдет до точки В. Как Er B(s) обозначим условие того, что в точке В произойдет ошибка. Тогда дадим определение ошибки для абстракции I¿ следующим образом следующим образом:

(5) Егг^ = (З*(РвЧЮ)) а V* (РвЧЮ -> Еггв(ю)

Тогда наличие ошибки в точке В определим, как существования абстракции, на которой произойдёт ошибка:

(6) = Егг*

Данную формулу будем называть общим определением ошибки, <{!;}, Еггв ) -определением ошибки, полученным подстановкой {!;} и Еггв в общее определение ошибки. В зависимости от выбора множества абстракций {!;} будут различаться множества обнаруживаемых ошибок. Рассмотрим два множества абстракций Е' = и X" = {£,•'}' £'Д" £ 2Е таких, что:

(7) VI Э/:2; = и7-е/2;'

Пусть Еггд - множество ошибок в точке В для множества абстракций Е', Еггв - для 2 , тогда если (7) верно, то:

(8) У В : £гг|' Е Ягг|"

т.'

Для доказательства (8) заметим, что если верна Еггв \ то для всех £ !.[, при

2" _ 2"

условии достижимости Рв7 (х), будет верна и Еггв' . Так как Рв1($) -

е", _

выполнима, а = то среди Щ' найдется такой Еу, что Рв} (х) -

выполнима. Тогда подставляя I = / в (6) получим верную формулу. Таким образом, определение ошибки (6) позволяет проводить сравнение различных методов обнаружения ошибок. Рассмотрим несколько используемых на практике вариантов задания абстракций {Е;}. Рассмотрим множество I, пронумеруем все его элементы Е = {о[}. Зададим = <7;. Тогда для данного варианта разбиения формула (6) принимает вид: (9)Э<7г:Рв(<7г)ЛЯггв(<7г) Формула (9) эквивалента формуле (1), т.к. задает значения символьных переменных параметризации. Таким образом формула (6) для разбиения Е; = £7; формулирует задачу символьного выполнения для автоматической генерации тестов.

С другой стороны, в качестве множества абстракции можно взять один элемент Ех = I. Тогда формула (6) примет вид:

(10) 3з(Рв(Ю) А V* (Рв(5) -> Еггв(Ю)

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

По числу обнаруживаемых ошибок между абстракциями Z¿ = a¿ и Z¿ = Рв находится абстракция путей выполнения. Идея данной абстракции основана на предположении, что контракт функции не запрещает пути выполнения в графе развертки. Иными словами, для каждого пути в графе развертки найдется способ запустить рассматриваемую функцию таким образом, чтобы управление прошло именно на данном пути.

Для построения абстракций путей выполнения, каждому булевому выражению в графе развертки сопоставим свою булеву переменную {bj}. По построению, каждая из булевых переменных зависит параметризации, т.е. bj = b¡(s ), тогда:

Таким образом, каждая задает значения всех булевых выражений, которые в свою очередь однозначно определяет путь выполнения в графе развертки. Формула (6) для данной абстракции имеет следующий вид:

Заметим, что для введённых абстракций верно следующее соотношение:

Между абстракциями ^ = Рв и ^ = Ь; находятся абстракции к критических точек. При использовании абстракции к критических точек точка В считается ошибочным в том случае, если найдутся к точек графа развертки таких, что любой путь проходящий через них и через В приводит к ошибке. Как можно заметить, при достаточно большом числе к, данная абстракция будет эквивалентна абстракции = Ь¿. Рассмотрим случай к = 1. Пронумеруем все точки в графе развертки - {В¿}, тогда = Рв., а РВ1 = Рв. А Рв. Тогда общая формула ошибки записывается следующим образом:

Учитывая последнюю введённую абстракцию, напишем итоговое соотношение:

Где Рв (s) = (Vi b¿ = b¿(S)) A P¡

в

(13) Егг^1=Рв Е Err^í=bl Е Err^i=rTi

(14) 3Во (з5 (р/ЧЮ)) A VS (р/ЧЮ -> ErrB(s))

(15) Ягг^"2 Е ErrXi~PBi Е ErrI'í~bl Е Er E¡:

4. Примеры ошибочных ситуаций

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

1) public string Examplel(object obj)

2) {

В) obj = null;

4) return obj.ToString();

5) }

1) public string Example2(object obj, bool a)

2) {

3) if (a) {

4) obj = null;

5) }

6) return obj.ToString();

7) }

1) public string Example3(object obj, bool a, bool b)

2) {

3) if (a) {

4) obj = null;

5) }

6) if (b) {

7) return obj.ToString();

8) }

9) return null;

10)}

1) public string Example4(object obj, bool a, bool b, bool c)

2) {

3) if (a) {

4) obj = null;

5) }

6) if (b) {

7) obj = new object();

8) }

9) if (c) {

iНе можете найти то, что вам нужно? Попробуйте сервис подбора литературы.

10) return obj.ToString();

11) }

12) return null;

13)}

1) public string Example5(object obj)

2) {

3) return obj.ToString();

4) }

Листинг 1. Примеры различных ошибочных ситуаций.

Listing 1. Examples of defects.

На листинге 1 приведены пять различных потенциально ошибочных ситуаций. В качестве условия ошибки рассмотрим условие obj == null. Тогда Examplel будет являться ошибочным для всех абстракций.

Example2 является ошибочным для всех абстракций, кроме = I. Однако, если в качестве условия ошибки использовать не условие равенства null в точке разыменования (6), а условие разыменования в точке присваивания (4), то определение ошибки при Ij = I также обнаружит ошибку. Example3 также является ошибочным для всех абстракций, кроме Ij = I, однако в отличие от Example2 определение Ij = I не обнаружит ошибку в данном случае при переносе ошибочной точки в присваивание. В Example4 ошибку обнаружат только абстракции = Ь; и = о^. Абстракция = Pbi не найдет ошибку, т.к. критической точкой для данной абстракции является точка (4), однако между точками (4) и (10) существует путь (4)-(7)-(10) не содержащий ошибок. Следовательно, по определению (14) данная ситуация не является ошибочной.

Наконец, в Example5 ошибку обнаружит только абстракция Ij = at.

5. Примеры алгоритмов поиска ошибочных ситуаций

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

(16) Errhi = 0 E Errhi E Er E ••• Errhi E Err

будем говорить, что А относится к классу Errsi, если Er А Е Err^i, но Er А <£

yk-i

Err i . Заметим, что в данном случае допускается пропуск ошибок класса ук

Err i, однако алгоритм А должен находить некоторый набор ошибок, таких что они принадлежат Er , но не содержатся в Err^i

Заметим, что набор ошибок, обнаруживаемых алгоритмом А, может не совпадать с набором выдаваемых им предупреждений. Для предупреждения wA будем говорить, что оно является ошибкой, если wA 6 Er 2i=cri. Рассмотрим построенные во второй главе абстракции: 112

(17) Err^i = 0 Е ErrE¡~E Е Егг^1~Рв1 Е ErrEi_6¡ Е £rr

Примером алгоритма поиска ошибок, относящихся к классу I¿ = I является анализ критических рёбер, реализованный в анализаторе Svace [7]. В качестве условия возникновения ошибки для поиска разыменования нулевого указателя в программах на C/C++ используется следующее условие:

(18)Errx = (х = null) А (dereference(х))

Где dereference(х) - условие того, что символьное значение х будет использовано в операции разыменование далее в графе развертки. Условие dereference (х) может быть вычислено с помощью обратного анализа графа развертки.

Алгоритм, использующийся в анализаторе Svace для поиска разыменования нулевого указателя, основан на вычислении для каждой точки условий null(x) = {T,F}, deref{x) = {T,F}. Условие null(x) истинно в том случае, если в данной точке символьная переменная х всегда равна null. Соответственно, deref(x) истинен в том случае, если символьная переменная х будет гарантированно разыменована. Тогда, если найдется такая точка В в графе развертки G', что для какой-либо переменной х одновременно верны null(x) A derefÇx), то в точке В происходит ошибка.

Покажем, что данный алгоритм относится к классу Z¿ = I. Для этого достаточно показать, что если данный алгоритм находит ошибку, то она соответствует определению (L¿ = Y.,Errx). Действительно, если для точки В верно одновременно null(x) A derefÇx), то на любом пути выполнения будет верно Errx = (х = null) A (dereference (х)). Однако определение (Z¿ = Y.,Errx) предполагает, что точка В достижима из точки входа. Данный алгоритм не проводит анализ достижимости, поэтому он будет выдавать предупреждения даже в случае недостижимого кода. Предупреждения в недостижимом коде не содержатся в Ег 2*£=СГ£, поэтому они не включаются в общее множество ошибок алгоритма, следовательно ошибки данного алгоритма включены в (Z¿ = I, Ег х).

Рассмотрим алгоритм поиска ошибки разыменования нулевого указателя по определению (Z¡ = b¿,Er Deref^x) = (x = null)). Пусть для каждой вершины графа развертки посчитаны условия NullB{b), такие, что Nullg(b) -> х = null. Запись Nullg{b) означает, что условие ошибки зависит от значений булевых выражений

Алгоритм выдает в точке В ошибку в том случае, если формула разрешима:

(19) Nullg(bi(s )) A PB(s). Покажем, что все ошибки найденные данным алгоритмом являются ошибками по определению определения (Z¡ = b¿,ErrDегедЖ) = (х = null)).

Так как формула NullB(b(s )) APB(s) разрешима, то найдется такое s', что Null%(b(s')) APB(s') - верно. Пусть Ь' = b(s'), тогда подставив в формулу (12) b = b' получим:

(20) (bs ((vi b{ = bKs)) A PB(s)))

Л Vs (jvi b[ = b[{s)) A PB (s) —> x = null)

Заметим, что первый конъюнкт формулы (20) верен, т.к. взяв s = s' получим верное равенство. Осталось доказать, что:

(21) Vs ((vi Ь[ = b¿(s)) APB(s) -> x = null)

Для этого докажем следующее утверждение:

(22) (Vi b[ = b¡(s)) APB(s) -> NullxB(b) Л PB(s)

Так как s' является решением для (20), а Ь' = b(S'), то NullB(b') - верно. Условие (vi b[ = b¿(S)) означает, что Ь' = Ь(х'), отсюда получаем, что (vi b[ = b¿(s)) -> NullB(b). Следовательно, исходная импликация (22) верна. Учитывая, что из NullB(b) Л PB(s) -> х = null, получаем, что формула (21) также верна. Таким образом доказано, что результаты данного алгоритма включены в (Z¡ = b¿, Err^^f^^ = (х = null)}.

Количество срабатываний, выдаваемых алгоритмом напрямую зависит от вида условия NullB. Вообще говоря, условие NullB может быть построено точно, т.е. результаты такого алгоритма совпадут с (Z¡ = b¿,ErrDеге/(Ж)Ж = (х = null)}. На практике, в инструментах Svace [7] и SharpChecher [6], используются неполные реализации, пропускающие часть срабатываний по сравнению (Z¡ = bit ErrDere^x^x = (х = null)). Однако, в соответствии с классификацией данные реализации всё равно относятся к (Z¡ = bi.Er Dere/(X)X = (х = null)), т.к. обнаруживают ошибки в Example4. В качестве примера алгоритма поиска £,rrE¡=PBí, может быть использован алгоритм поиска Er 2l=¿í, который в случае обнаружения ошибки дополнительно проверяет её принадлежность к классу Errl:i=PBi.

5. Применения предложенной классификации

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

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

Набор различных определений ошибочных ситуаций можно использовать для анализа и сравнения алгоритмов поиска ошибок. Наличие формальных определений ошибочных ситуаций позволяет проводить формальное доказательство соответствия предложенных алгоритмов анализа программ. Кроме того, предложенные определения ошибок могут сами использованы как алгоритмы поиска ошибок. Построенные формулы, описывающие ошибочные ситуации, могут быть переданы сторонним SMT-решателям, которые проверят их на совместность. В случае, если формула является совместной, SMT-решатель предоставит явное решение, описывающее абстракцию на которой происходит ошибка. Данная абстракция может быть предъявлена пользователю, в качестве примера ошибочной ситуации.

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

6. Заключение

В данной работе рассмотрен вопрос формализации ошибочных ситуаций для статического символьного выполнения. Рассмотрена общая формула ошибочных ситуаций. Разобраны частные определения ошибочных ситуаций, а также алгоритмы их поиска, использующиеся в анализаторах кода Svace и SharpChecker. Разработана классификация алгоритмов поиска ошибок на основе набора определений ошибочных ситуаций. Для рассматриваемых алгоритмов поиска ошибок проведена их классификация, включая доказательство соответствия. Приведены примеры использования данной формализации на практике.

Список литературы

[1]. Y. Xie, A. Aiken. Saturn: A Scalable Framework for Error Detection Using Boolean Satisfiability ACM Trans. Program. Fang. Syst. 2007. Vol. 29, no. 3.

[2]. F. Ivancic, G. Balakrishnan, A. Gupta at al. Scalable and scope-bounded software verification in Varvel. Automated Software Engineering. 2015. Vol. 22, no. 4. pp. 517-559.

[3]. Babic D., Hu A.J. Calysto. Software Engineering, 2008. ICSE '08. ACM/IEEE 30th International Conference on. 2008. May. pp. 211-220.

[4]. B.K. Кошелев, И.А. Дудина, В.И. Игнатьев, А.И. Борзилов. Чувствительный к путям поиск дефектов в программах на языке С# на примере разыменования нулевого указателя. Труды ИСП РАН, том 27, вып. 5, 2015 г., стр. 59-86. DOI: 10.15514/ISPRAS-2015-27(5)-5

[5]. J. King. Symbolic Execution and Program Testing. Commun. ACM. 1976. Vol. 19, no. 7. pp. 385-394.

[6]. В. К. Кошелев, В. H. Игнатьев, А. И. Борзилов. Инфраструктура статического анализа программ на языке С#. Труды ИСП РАН, том 28, вып. 1, 2016 г., стр. 21-40. DOI: 10.155144SPRAS-2016-28(1 )-2

[7]. В.П. Иванников A.A. Белеванцев А.Е. Бородин В.Н. Игнатьев Д.М. Журихин А.И. Аветисян М.И. Леонов. Статический анализатор Svace для поиска дефектов в исходном коде программ. Труды ИСП РАН, том. 26, вып. 1. pp. 231-250. DOI: 10.15514/ISPRAS-2014-26(1 )-7

[8]. И.А. Дудина, В.К. Кошелев, А.Е. Бородин. Поиск ошибок доступа к буферу в программах на языке C/C++. Труды ИСП РАН, том 28, вып. 4, 2016 г., стр. 149-168. DOI: 10.15514/ISPRAS-2016-28(4)-9

Formalization of Error Criteria for static symbolic execution

V.K. Koshelev <vedun@ispras.ru> Institute for System Programming of the Russian Academy of Sciences, 25, Alexander Solzhenitsyn St., Moscow, 109004, Russia

Abstract. This paper is devoted to the formalization of the error criteria for program static analysis, based on symbolic execution. Using the original error criteria of symbolic execution approach in program static analysis leads to an excessive number of false positives. To solve this problem, we propose an alternative definition of the error criteria. Proposed definition reports errors only if they occur on a certain set of input variables. Examples of such sets are the set of values of input variables in which control will pass through a given point of the program, or set of values in which the controls take place along a given path in the control flow graph. This paper discusses the various ways to specify such sets of initial values, including analysis of the final error criteria. We overview algorithms corresponding to the error criteria and prove their correctness. Finally, we consider the practical applications of the given error criteria, which include classification of the warnings generated by static analysis tools; taking into account unknown function contracting, especially preconditions; using the proposed error criteria as formulas for a SMT-solver. The latest application allows to get the precise solution of the particular error criteria, including the error trace.

Keywords: static analysis, error criteria, symbolic execution.

DOI: 10.15514/ISPRAS-2016-28(5)-6

For citation: V.K. Koshelev. Formalization of Error Criteria for static symbolic execution. Trudy ISP RAN/Proc. ISP RAS, 2016, vol. 28, issue 5, 2016, pp. 105-118 (in Russian). DOI: 10.15514/ISPRAS-2016-28(5)-6

References

[1]. Y. Xie, A. Aiken. Saturn: A Scalable Framework for Error Detection Using Boolean Satisfiability ACM Trans. Program. Lang. Syst. 2007. Vol. 29, no. 3.

[2]. F. Ivancic, G. Balakrishnan, A. Gupta at al. Scalable and scope-bounded software verification in Varvel. Automated Software Engineering. 2015. Vol. 22, no. 4. pp. 517-559.

[3]. Babic D., Hu A.J. Calysto. Software Engineering, 2008. ICSE '08. ACM/IEEE 30th International Conference on. 2008. May. pp. 211-220.

[4]. V. Koshelev, I. Dudina, V. Ignatyev, A. Borzilov. [Path-Sensitive Bug Detection Analysis of C# Program Illustrated by Null Pointer Dereference], Trudy ISP RAN/Proc. ISP RAS, vol. 27, issue 5, 2015. pp. 59-86 (in Russian). DOI: 10.15514/ISPRAS-2015-27(5)-5

[5]. J. King. Symbolic Execution and Program Testing. Commun. ACM. 1976. Vol. 19, no. 7. pp. 385-394

[6]. V. Koshelev, V. Ignatyev, A. Borzilov. C# static analysis framework. Trudy ISP RAN/Proc. ISP RAS, vol. 28, issue 1, 2016, pp. 21-40 (in Russian). DOI: 10.15514/ISPRAS-2016-28(1 )-2

[7]. V.P. Ivannikov, A.A. Belevantsev, A.E. Borodin, V.N. Ignatiev, D.M. Zhurikhin, A.I. Avetisyan, M.I. Leonov. Static analyzer Svace for finding of defects in program source code. Trudy ISP RAN/Proc. ISP RAS, vol. 26, issue 1, 2014, pp. 231-250 (in Russian). DOI: 10.15514/ISPRAS-2014-26(l)-7

[8]. I. Dudina, V. Koshelev, A. Borodin. [Statically detecting buffer overflows in C/C++Proceedings of the Institute for System Programming], Trudy ISP RAN/Proc. ISP RAS, vol. 28, issue 4, 2016, pp. 149-168 (in Russian).

i Надоели баннеры? Вы всегда можете отключить рекламу.