Моделирование памяти с использованием неинтерпретируемых функций в предикатных абстракциях

Труды ИСП РАН, том 27, вып. 5, 2015 г..

Моделирование памяти с использованием неинтерпретируемых функций в предикатных абстракциях1

М.У. Мандрыкин <mandrykin@ispras.ru>

В.С. Мутилин <mutilin@ispr as.ru>

ИСП РАН, 109004, Россия, г. Москва, ул. А. Солженицына, дом 25

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

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

1. Введение

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

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

Подход ограничиваемой проверки моделей (от англ. Bounded Model Checking, ВМС) [1, 2] основывается на разворачивании циклов программы на конечное фиксированное число шагов к и последующей проверке возможности нарушения проверяемого свойства на глубине, не большей, чем

1 Исследование проводилось при финансовой поддержке РФФИ в рамках проекта №15-01-03934

117

Trudy ISP RAN [The Proceedings of ISP RAS], vol. 21, issue 5, 2015.

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

В методе ВМС ограничение сверху числа к существенно используется при моделировании памяти. Так как программа представляется конечным множеством конечных путей, то на каждом из них можно раскрыть выражения с разыменованием указателей, подставив вместо переменных-указателей выражения, определяющие их значения на этом пути [3]. Так как путь конечен, то можно с помощью таких подстановок прийти к выражению, в котором отсутствуют указатели. Исключения составляют лишь массивы, для моделирования которых вводятся неинтерпретируемые функции.

Метод ВМС позволяет поддерживать для языка программирования широчайший набор конструкций, включая выражения с указателями, в том числе указатели на структуры, массивы, адресную арифметику, но так как рассматриваются только конечные пути, то рекурсивные структуры данных поддерживаются на конечную глубину (см. Табл. 1). На сегодняшний день метод ВМС является наилучшим методом для поиска неглубоких (в смысле длины пути выполнения) ошибок. Инструменты, реализующие этот метод, такие как СВМС[1] и F-SOFT[4], с успехом используются для поиска ошибок при разработке полупроводниковых устройств, для которых схемы часто моделируются программой на языке высокого уровня (например, С), а также в системном программном обеспечении, например, в автомобильной промышленности [5].

Вторая группа методов основана на подходе уточнения абстракции по контрпримерам (от англ. CounterExample-Guided Abstraction Refinement, CEGAR) [6,7]. Инструменты, основанные на данном подходе, пытаются доказать некоторые свойства исходно заданной системы, предварительно ее упростив. Упрощенная система при этом, как правило, не обладает всеми свойствами исходной и поэтому в дальнейшем может потребоваться процесс ее уточнения. В общем случае к упрощенной системе — абстракции — предъявляется требование корректности (англ, soundness). Оно заключается в том, что свойства, доказанные для абстракции, должны быть верны и на исходной системе. Однако не все свойства, верные для исходной системы, верны для абстракции. В абстракции может быть обнаружено нарушение одного из проверяемых свойств, то есть контрпример, который не является осуществимым в исходной системе. Для исключения таких контрпримеров используется уточнение абстракции.

Процесс верификации с использованием уточнения абстракции по контрпримерам начинается с построения неточной (грубой) абстракции исходной системы и продолжается одним или несколькими уточнениями. 118

Труды ИСП РАН, том 27, вып. 5, 2015 г..

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

неосуществимости контрпримера используется для уточнения абстракции, и ее проверка снова повторяется.

В качестве абстракции программы будем рассматривать предикатные абстракции [8]. Предикатная абстракция программы основывается на разбиении всего множества состояний программы на подмножества с одинаковыми наборами значений выбранных предикатов. При этом предикаты в абстракции могут комбинироваться либо только с использованием конъюнкций (в таком случае предикатная абстракция называется декартовой), либо в том числе с использованием дизъюнкций (в таком случае абстракция называется булевой). Проверка контрпримера и пересчет абстракции осуществляется на основе представления последовательностей инструкций исходной программы в виде некоторых логических формул. Для решения формул используются различные решатели формул в теориях (англ. Satisfiability Modulo Theories, SMT). Для уточнения абстракции новые предикаты извлекаются из невыполнимых формул. Среди способов их извлечения имеются синтаксические [9] методы, а также интерполяция Крейга [10, 11]. Для поиска интерполянтов Крейга на практике применяются интерполирующие решатели формул в теориях, такие как CSISAT [12] и MATHSAT [13,14].

Рассмотрим методы реализации поддержки указателей в CEGAR-инструментах. Первый метод основан на анализе алиасов. В программировании словом алиас (от англ, alias — имя, прозвище) описывается ситуация, при которой какая-либо ячейка с данными в памяти программы оказывается доступна в исходном тексте (коде) под различными обозначениями (именами). Таким образом, изменение данных с использованием одного из таких обозначений неявно ведет к изменению значений, доступных по всем остальным обозначениям той же ячейки памяти. Информация об алиасах используется для генерации ограничений, накладываемых на состояние памяти операцией присваивания, в формулах контрпримера и при пересчете абстракции. Для каждого возможного алиаса цели операции присваивания генерируется проверка, является ли его адрес равным адресу цели. В зависимости от результата этой проверки с помощью логических формул выражается либо обновление соответствующего выражения-алиаса, либо сохранение прежнего значения этого выражения. Такой метод был реализован в инструменте BLAST 2.5 [15-17]. Анализ алиасов в нем осуществляется в терминах анализа Андерсена [18]. Для хранения и выполнения запросов к информации об алиасах используется представление BDD и алгоритм, похожий (но не совпадающий) с алгоритмом в [19]. Для того чтобы выписывать ограничения в формуле на состояния

119

Trudy ISP RAN [The Proceedings of ISP RAS], vol. 27, issue 5, 2015.

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

В инструменте BLAST 2.7 [20] метод улучшен так, что в формулу для оператора присваивания добавляются только алиасы, влияющие на ее выполнимость, которые определяются по выражениям, использованным в последующих операторах на пути. Таким образом стало возможно поддерживать произвольную глубину разыменований для указателей и структур. Однако в инструменте все еще не поддерживаются массивы, адресная арифметика и рекурсивные структуры данных.

Анализ рекурсивных структур данных (shape analysis) — это метод статического анализа программ, который позволяет находить и проверять свойства динамически выделяемых структур данных. Он обладает достаточно большой точностью при анализе различных соотношений между указателями в программе и динамически размещаемыми в памяти структурами данных, в том числе при анализе выражений с указателями. Однако, имея высокую точность, этот подход является достаточно плохо масштабируемым. Так, например, представленный на соревновании SV-COMP 2014 [21] инструмент PREDATOR [22], который реализует данный вид анализа на основе символьных графов памяти (англ. Symbolic Memory Graphs, SMG), набрал 50 баллов из 2766 в категории, соответствующей реальным драйверам ОС Linux. Разработка другого инструмента, BLAST, реализующего ленивый анализ рекурсивных структур данных [23] на основе предикатов троичной логики (three-valued logic) [24], к моменту написания данной статьи не велась уже в течение нескольких лет.

Таблица 1. Сравнение инструментов статической верификации.

Инструмент/подход Указатели Структуры Массивы Рек. структуры данных Адресная арифметика Масштабир.

Ограничиваемая проверка моделей (ВМС) + + + ± (конечная глубина) + "

BLAST 2.5, алиасы с замыканием ± (конечная глубина) ± (конечная глубина) "   +

BLAST 2.7, алиасы с бесконечным замыканием + + " ± (конечная глубина)  +

BLAST, ленивый анализ рекурсивных структур данных + + " +  ?

120

Труды ИСП РАН, том 27, вып. 5, 2015 г..

CPAchecker, модель + + ± ± + +

памяти на основе (огранич. (конечная

неинтерпретируемых функций размер) глубина)

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

2. Обзор метода

Для реализации метода был выбран инструмент верификации CPAchecker, основанный на подходе CEGAR с использованием булевой предикатной абстракции и интерполяции Крейга для получения новых предикатов при уточнении абстракции. Для решения задач проверки выполнимости формулы пути и интерполяции Крейга в CPAchecker используются интерполирующие решатели MATHSAT 5, SMTINTERPOL, Z3, PRINCESS. Все эти решатели поддерживают бескванторные теории вещественной или целочисленной линейной арифметики и равенства с неинтерпретируемыми функциями, но не поддерживают (либо не полностью поддерживают, как MATHSAT 5) теорию массивов. Поэтому в данной работе разрабатывался и исследовался способ построения формулы пути с использованием только неинтерпретируемых функций.

В разработанном подходе состояние памяти программы представляется в виде неинтерпретируемой функции f отображающей некоторые условные адреса переменных в памяти в их значения. Для неинтерпретируемых функций выполнена аксиома конгруэнтного замыкания отношения эквивалентности Va. Vb. ((a = Ь) -» /(a) = /(b)). Эта аксиома моделирует равенство значений, полученных после разыменования равных указателей при одном и том же состоянии памяти программы. То есть если есть два равных указателя pi и р2, то значения *р1 и *р2 также равны.

При записи значения по какому-либо адресу (*е = ехрг) происходит смена версии неинтерпретируемой функции, представляющей состояние памяти.

121

Trudy ISP RAN [The Proceedings of ISP RAS], vol. 27, issue 5, 2015.

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

е = aV/j (a) = /j_i(a),

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

Для представления адресов в памяти предлагается использовать суммы вида b + п, где b — переменная (неинтерпретируемая константа), соответствующая адресу некоторой сущности (переменной, структуры, объединения или массива) верхнего уровня, называемая базовым адресом, п — смещение рассматриваемой переменной относительно сущности верхнего уровня. При таком представлении для адресов сущностей верхнего уровня необходимо выполнение условий положительности и непересечения внутренних адресов. Эти условия предлагается записывать в виде двух аксиом модели памяти:

b>0

В

где b — переменная, представляющая базовый адрес сущности, к — целое число, уникальное для каждой такой переменной, п — смещение относительно начала сущности, принимающее значения от 0 до s-1 включительно, где s — размер сущности.

Экземпляры (А2) позволяют задать всевозможные попарные неравенства внутренних адресов. Докажем, что из В(Ьг + щ) = к1,В(Ь2 + п2) = к2 и /с, Ф к2 следует, что Ъ1 + щ Ф Ъ2 + п2. Пусть Ьг + щ = Ь2 + п2, тогда из (А2) получаем В(Ь1 + щ) = В(Ь2 + п2), кг = к2 - противоречие с ^1 ^ ^2-

2.1 Полнота предлагаемого метода

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

122

Труды ИСП РАН, том 27, вып. 5, 2015 г..

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

3. Определения

3.1 Программы и поток управления

Мы ограничимся рассмотрением простого императивного языка программирования (аналогично [25, 26]), в котором все переменные имеют типы int и int*. а все операции — это либо присваивания, либо предположения assume, представленные в Таблице 2. Мы рассмотрим программы без вызовов функций, хотя описанный подход может быть расширен на программы с несколькими функциями2.

Программа представляется автоматом потока управления (АЛУ) (от англ, control-flow automaton, CFA). АПУ A=(L,G) состоит из множества точек программы L, моделирующих счетчик команд, и множества дуг потока управления С с [ х Ops х L, которые моделируют действия, выполняемые при переходе из одной точки программы в другую. Множество переменных, встречающихся в операциях Ops, обозначим как А. Программа Р = (А, 10,1Е) состоит из АПУ A=(L,G) (моделирующего поток управления программы), начальной точки программы /„ 6 L (моделирует точку входа), и целевой точки программы 1Б (моделирует ошибочное состояние).

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

2 Реализация в инструменте CPAchecker работает с программами на языке С и под держивает вызовы функций

123

Trudy ISP RAN [The Proceedings of ISP RAS], vol. 27, issue 5, 2015.

адрес ячейки памяти в значение, содержащееся в ней. Так как переменные х £ X обозначают адреса ячеек памяти, то значения для переменной х будут представляться как f(x). Обозначим множество конкретных состояний программы как 8.

Множества г £ £ назовем регионами, которые будем представлять с помощью формул алгебры логики ф. Формулы будут содержать переменные из множества X, а также неинтерпретируемые функции из множества F, заданные над целыми числами (Z — Z), которые служат для моделирования состояния памяти. Формула ф представляет множество [[<д]] конкретных состояний данных с, для которых выполнено ф (т. е. [[<д]] = {с £ £ | с 1= ф})-

Конкретное состояние программы это пара (1,с), где I £ L точка программы, а с — это конкретное состояние данных. Пара (I, ср) представляет множество {(I, с) | с 1= <р] конкретных состояний. Конкретная семантика операции op £ Ops определяется оператором сильнейшего постусловия SPop (): для формулы ф оператор SPop(cp) представляет наименьшее по включению множество состояний, содержащее все состояния, получаемые хотя бы из одного состояния региона, представленного ф, после выполнения оператора ор.

Путь а — это последовательность ((ор1, Ц),(орп , 1п )) пар из операции и точки программы. Путь о называется путем программы, если он начинается в 10 (см. определение Р) и для каждого i, такого что 0 < i < п, существует дуга АПУ д = (NiТаким образом, о представляет синтаксический путь в АПУ.

Конкретная семантика для пути программы о = ((ор1,11),...,(орп,1п)) определяется как последовательное применение оператора сильнейшего постусловия для каждой операции: SP<y((p) = SPopn(... SPopi(<р)...). Формула SPa(.<P) называется формулой пути.

Множество конкретных состояний, являющихся результатом выполнения пути программы о представляется парой (ln,SPa(true)). Путь программы называется достижимым, если формула SPa(true') выполнима. Конкретное состояние программы (1п,сп) называется достижимым, если существует достижимый путь о, заканчивающийся в точке 1п, и такой, что сп И SPa(true). Точка программы / достижима, если существует конкретное состояние с, такое что (I, с) достижимо. Программа корректна (safe), если 1Е недостижимо.

3.2 Булевы предикатные абстракции

Пусть F — множество неитерпретируемых функций. Пусть р — множество предикатов из теории без кванторов над переменными программы X и неинтерпретируемыми функциями F. Формула ф — это булева комбинация

124

Труды ИСП РАН, том 27, вып. 5, 2015 г..

предикатов из р. Точность для формул — это конечное подмножество л: Ер. Точность для программы — это функция П : L -» 2*3, которая задает точность для формул в каждой точке программы.

Булева предикатная абстракция (ур)п для формулы ф — это сильнейшая булева комбинация предикатов из точности ж, которая следует из ф. Данная предикатная абстракция формулы ф, которая представляет регион конкретных состояний программы, используется как абстрактное состояние данных (абстрактное представление региона) в верификации программ. Для формулы Ф и точности ж булева предикатная абстракция (<р)п может быть вычислена с помощью запросов к SMT решателю с поддержкой ALL-SAT следующим образом. Каждому предикату pt £ п сопоставим булеву переменную vt. Затем сделаем запрос к решателю для выдачи всех векторов решений v1,...,V|7r| формулы <р APten(Pi ° vi)- Для каждого вектора решений мы строим конъюнкцию всех предикатов из ж, которые входят в вектор решения как истина. Дизъюнкция всех таких конъюнкций будет булевой предикатной абстракцией для формулы ф.

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

работах [27, 28, 7].

3.3 Кодирование с настраиваемым размером блока

В кодировании с настраиваемым размером блока (Adjustable-Block Encoding, ABE) предикатные абстракции не вычисляются при каждом переходе по дуге из АПУ, а напротив, вычисляются только в некоторых абстрактных состояниях, которые будем называть состояниями абстракции (другие абстрактные состояния будем называть состояниями без абстракции). На пути между двумя состояниями вычисления абстракции сильнейшее постусловие пути хранится во втором компоненте состояния, который мы назовем дизъюнктивной формулой пути. Таким образом, абстрактное состояние АВЕ содержит два компонента-формулы (ф,ср), где формула абстракции ф - это результат вычисления абстракции, а дизъюнктивная формула ф представляет сильнейшее постусловие с момента вычисления последнего состояния абстракции. Для заданной дуги АПУ g = (I, ор, Г) и абстрактного состояния (ф,ср), следующее состояние либо только расширяет формулу пути ф, либо вычисляет новую формулу абстракции ф и сбрасывает ф. Точки вычисления абстракции (и, таким образом, размер блока) определяется так называемым оператором настройки блока Ык. Если оператор blk(e,g) возвращает false (нет вычисления абстракции, т. е. абстрактное состояние е без абстракции), то следующее состояние (ф', ср') содержит ф' = ф (неизмененное) и ср' =

Более детально предикатные абстракции описаны в

125

Trudy ISP RAN [The Proceedings of ISP RAS], vol. 27, issue 5, 2015.

SPop(<p). Если оператор blk(e,g) возвращает true (e — состояние абстракции), то следующее состояние (ф', ср') содержит результат вычисления абстракции по формуле ф Аср, ф' = (sPop(<p А ф)^ и <р' = true как новую

дизъюнктивную формулу. Если <р А ф невыполнимо для состояния е, то е

недостижимо.

4. Модель памяти на основе неинтерпретируемых функций

Для моделирования памяти будем использовать неинтерпретируемые функции / (fm) и В. Имя неинтерпретируемой функции fm определим как конкатенацию имени / и индекса т: f m. Над формулами у|/ для неинтерпретируемых функций / и fm определим операцию подмены всех таких функций, содержащихся в формуле v|/ на новое имя fm,: ф[/т,] — заменяет все вхояедения / и /т на frn,.

Для задания модели памяти нам потребуются вспомогательные компоненты, которые будут храниться в абстрактном состоянии и изменяться при переходе к следующему состоянию. Во-первых, Alloc — множество пар (А,п) £ А х int, где константа А £ <А — представляет базовый адрес выделенной памяти, а число п — смещение относительно базового адреса. Во-вторых, т — индекс функции памяти/ В-третьих, к — последний индекс базовых адресов.

В модели памяти оператор сильнейшего постусловия задается как SPop((p) = ср А Г(ор), где Г(ор) определяется Таблицей 2.

Будем использовать вспомогательную функцию:

• memupdate(p, т', т, addrs) = Л (a,Qeaddrs ((Р = a + 0 V

fm'a+i= fma+i,

где е — это выражение без побочных эффектов и без разыменований указателей.

В выражениях *(sl + i), i имеет тип int.

Размер целого и указателей принимается равным 1 байту.

Иначе нужно в выражении *(s i i) в i указывать размер как количество элементов, помноженное на соответствующий размер элемента.

126

Труды ИСП РАН, том 27, вып. 5, 2015 г..

Таблица 2. Правила построения ограничений Г

Операция (ор) Индекс функции памяти m' Множество адресных переменных Alloc' Индекс базового адреса к' Ограничения Г

Выделение переменной на стеке int s; или int *s; He меняется А' — новое имя переменной. Alloc' = Alloc и {(Л',0)} к' — новый индекс s =А' ЛА'Х) ЛВ(А)=к'

Выделение памяти размера size в куче s = alloc

s = е m' — новый индекс Не меняется Не меняется fm,

*

si = *

assume p Не меняется Не меняется Не меняется Г

127

Trudy ISP RAN [The Proceedings of ISP RAS], vol. 27, issue 5, 2015.

4.1 Расширение подхода для структур

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

1. При выделении памяти alloc(size) для структуры А, размер size

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

2. Выражение доступа к полю s-fрассматривается как *(s + со (A, f)).

3. В присваивании структур по значению si = s2 необходимо выписывать ограничения для присваивания всех полей структуры.

4.2 Пример построения формулы пути

В примере программы используется макрос container of(p, type, field name), который раскрывается как (type)(p + (0 - (o(type, field name))). To есть для указетеля на вложенное поле структуры field пате, мы получаем указатель на структуру, содержащую это поле. Макрос container of часто используется в коде ядра ОС Linux и составляет большую сложность для инструментов, не поддерживающих адресную арифметику. Из-за этого возникают как ложные срабатывания, так и упущенные ошибки.

Пусть задана следующая программа: struct В { int a; int b; };

struct В *р; struct В *q; int *х; р =alloc(sizeof(B)); p->b = 1; х = &(р->а);

q = container_of(x, struct В, а); assume(p->b != q->b);

Программа содержит единственный путь, являющийся недостижимым, так как р- h == q->b и условие в последнем assume не выполнено. В данном примере при моделировании памяти требуется учитывать семантику арифметики указателей, иначе возможно ложное срабатывание, из-за того что путь может быть признан достижимым.

Для данного пути предварительно мы заменим операции со структурами на

128

Труды ИСП РАН, том 27, вып. 5, 2015 г..

операции с указателями и построим для него формулу пути.

Таблица 3. Пример построения формулы пути

Путь Построение формулы пути

т' Alloc' k' Г

struct В *р; 0 {(А0,0)} 1 p = AO aA0>0aB(A0) =1

struct В *q; 0 {(А0.0), (А1,0)} 2 q =A1 AAl > 0 AB(A1) =2

int *х; 0 {(А0,0), (А1,0), (А2.0)} 3 x =A2 AA2>0AB(A2) =3

Р =alloc(sizeof( struct В)); 1 {(А0,0), (А1,0), (А2,0), (АЗ,0),...,(АЗ, sizeof (struct В)-1)} 4 fi(.P) = лз AA3>0 aB(A3+i) = 4, 0 < i < sizeof (struct В) Л ((p = Ai + of) V (/iG4; + of) = fo(At + О;))), где (At,ot) £ Alloc

*(р + ш(В,Ь))= 1; 2 {(А0,0), (41,0), (42.0) , (43.0) ,..., (43, sizeof (struct В)-1)} 4 Wi(P)+a(B,b)) = 1 A ((fi(p) + to(B,b) = At + Oj) V (f2(Ai + °t) = fi(Ai + О;))), где (At,ot) E Alloc

х = р + со(В,а); 3 {(40,0), (41,0), (42.0) , (43.0) ,..„(43, sizeof (struct В)-1)} 4 fs(x) = f2(p) + o)(B,a) A ((x = At + of) V (f3(A( + Oj) = fziAi + of))), где (At,of) 6 Alloc

q = х + (0 -а>(В, а)); 4 {(40,0), (41,0), (42.0) , (43.0) ,.. „(43, sizeof (struct B)-1)} 4 Ш) = fs(x) ~ oi(B,a) A ((q = At+ of) V (f4(At + Oi) = f3(At + ог))), где (Аг,о() 6 Alloc

assume *

Таким образом, мы получим формулу пути SP„(true), являющуюся конъюнкцией формул в столбце Г. Эта формула является невыполнимой, что подтверждает недостижимость данного пути, что и требовалось показать в приведенном примере.

129

Trudy ISP RAN [The Proceedings of ISP RAS], vol. 27, issue 5, 2015.

4.3 Конфигурируемый анализ (CPA) с моделью памяти на основе неинтерпретируемых функций

Формализуем анализ с моделью памяти на основе неинтерпретируемых функций в виде конфигурируемого анализа (Configurable program analysis, CPA) [29]. Эго позволяет использовать гибкость операторов СРА для описания анализа без изменения основного алгоритма (см. Алгоритм СРА на Рис. 1).

Конфигурируемый анализ Ш) = (D,^, merge, stop) состоит из абстрактного домена D, отношения перехода оператора merge, оператора stop, определяемых следующим образом.

Пусть задана программа Р = (A, lQ, 1Е). где X — обозначает множество переменных используемых в программе Р, F — множество неинтерпретируемых функций, используемых для моделирования памяти, р — множество предикатов без кванторов над переменными X и функциями F, и П: L -* 2*° — точность предикатной абстракции.

1. Абстрактный домен D = (С, R, [[]]) — это тройка, состоящая из множества конкретных состояний С, полурешетки R = ([Е, Т, Е,и) и функции конкретизации [[]] : Е -» С.

Элементы решетки также называются абстрактными состояниями и являются семерками (1,ф,1^,(p,Alloc,k,m), где первые четыре компонента являются стандартными компонентами анализа АВЕ, 1,1^ 6 (L и ft-}); ф,<р е р. Компонент I моделирует счетчик команд, формула абстракции \|/ — булева комбинация предикатов, заданных в Я, — точка в программе, в которой была вычислена абстракция \|/, а ср — это дизъюнктивная формула, представляющая некоторые или все пути из точки 1^ в I. Заметим, что в состоянии абстракции всегда I = № и <р = true.

Для уточненной модели памяти мы ввели три новых компонента. Во-первых, Alloc — множество пар (А, п) 6 Л х int, где А 6 <Л — представляет базовый адрес выделенной памяти, а число п — смещение относительно базового адреса. Во-вторых, m — индекс функции памяти/ В-третьих, к — последний индекс базовых адресов.

Верхний элемент решетки — это абстрактное состояние Т = (1Т, true, lT, true, {}, 0,0). Частичный порядок с с Е х Е определяется так, что для любых двух состояний е1 = (l1,xf)1,l'l>1,(p1,Alloc1,k1,m1) и е2 = (12г Ф2> (Рг* А11°с2, к2,Шг) из Е выполнено:

ei — е2 =

Заметим, что мы подменяем все вхождения версий памяти в формулах абстракции ф, [f ] и ф2 [Я на одинаковую версию/

Оператор соединения W- Е х Е -» Е выдает наименьшую верхнюю грань двух операндов в соответствии с частичным порядком Е.

130

Труды ИСП РАН, том 27, вып. 5, 2015 г..

Алгоритм СРА

Вход: СРА Ш) = (D, merge, stop), начальное состояние е0 £ Е, где Е обозначает множество элементов решетки D Выход: множество достижимых абстрактных состояний Переменные: множество reached достигнутых элементов из Е, множество waitlist элементов из Е

1

2

3

4

5

6

7

8

9

10 11 12

13

14

15

16

waitlist := {е0} reached := {е0} пока waitlist Ф 0 делать выбрать элемент е из waitlist waitlist := waitlist \ {е} для каждого е' такого что е ** е' делать для каждого е" £ reached делать //слияние с существующими абстрактными состояниями enew'-= тегде(е',е") если enew Ф е" то

waitlist := (waitlist U {enew}) \ (e"} reached := (reached U {enew}) \ (e"} если -istop(e’, reached) to waitlist := waitlist и (e'} reached := reached U (e'} вернуть reached

Рис. 1. Алгоритм конфигурируемого анализа

2. Отношение перехода ** с ExGxE содержит все дуги (е,д, е'), где е = (l,xp,l^,q),Alloc,k,m), е' = (V,ф',q>', Alloc',k',т') и д = (1,ор,1') для которых выполнено:

(<р' = SPop(tp)) л (4»' = ф) Л (1*' = 1Ф) иначе

(ф' = true) Л

В представленной модели памяти оператор сильнейшего постусловия задается как SPop(<p) = ср А Г(ор), где Г(ор) определяется таблицей 2. При этом значения Alloc', к', т' в следующем состоянии определяются также по таблице

2.

Таким образом, мы имеем отношения перехода, которое работает в двух режимах, определяемых оператором blk: Е х G -» В, который отображает абстрактное состояние е и дугу g АПУ в true или false. Оператор Ык задается как параметр анализу. В первом режиме строится абстракция, а во втором вычисляется только сильнейшее постусловие.

131

Trudy ISP RAN [The Proceedings of ISP RAS], vol. 27, issue 5, 2015.

3. Оператор слияния merge-. E x E -» E для двух абстрактных состояний ei = (li,ipi,l^1,(Pi,Alloc1,k1,m1) и е2 = ((2,02<^2 • (Р2’А11ос2,к2,т2) определяется следующим образом: merge(elt е2) =

Г если

1 e2, иначе

где m' — новый индекс функции памяти, а функция memunchanged определяется как:

• mem_unchanged

Таким образом, множества адресных переменных объединяются, а при построении новой дизъюнктивной формулы вводится новый индекс функции памяти, к которой приравниваются функции в каждом из состояний.

4. Оператор останова stop-. Е х 2е -» В проверяет, покрывается ли состояние е другим состоянием из пройденных состояний R (множество reached)'.

Ve 6 E,R £ Е: stop

5. Оптимизации

Эффективность модели памяти сильно зависит от количества дизъюнкций, выписываемых в mem update из Таблицы 2. В предлагаемом подходе используются следующие оптимизации для сокращения числа этих

дизъюнкций:

1. Разделение области памяти по типам, так что каждая неинтерпретируемая функция задает отображение адресов переменных в их значения для одного соответствующего ей примитивного типа данных. Например, вводятся функции f long int, f char*, / struct В*. Примитивными, то есть не составными типами данных в данном подходе, считаются символьный и целочисленный типы, а также любой тип указателя. Таким образом, неявно предполагается, что значение, записанное по какому-либо адресу в качестве значения какого-то типа данных не может быть впоследствии считано по этому же адресу как значение другого типа. Это предположение является одним из ограничений подхода.

2. Выделение среди множества всех переменных программы подмножества «чистых» переменных, к которым возможен доступ лишь по именам (то есть переменных, не имеющих алиасов). Для таких переменных нет необходимости в использовании неинтерпретируемых функций для представления значений. Поэтому для них используется сходное с используемым инструментами BLAST и CPAchecker SSA-представление (для них не выписывается

132

Труды ИСП РАН, том 27, вып. 5, 2015 г..

разыменование и имя переменной представляет значение переменной, а не ее адрес). Определение «чистых» переменных возможно проводить не для всей программы, а на заданном пути, до тех пор пока не встретиться взятие адреса для этой переменной на этом пути или на другом пути при выполнении оператора merge.

3. Использование эвристики для полей структур. В предлагаемом подходе предполагается, что указатель на поле структуры, получаемый сложением адреса структуры с соответствующим смещением поля, может принимать только значения адресов того же самого поля в других структурах того же самого типа, что и структура, которой это поле принадлежит. Такой указатель не может, в частности, быть равным адресу элемента массива или отдельной переменной, не являющейся полем структуры. Например, обновление поля skbl->next не может повлиять ни на какой skb2->prev, даже если next и prev одного типа. В этом случае в качестве оптимизации мы опускаем посыл импликации в memupdate, если смещения заранее не равны. Такое предположение также является одним из ограничений метода.

4. Инициализация константами. Оптимизация заключается в том, что мы выписываем одно обновление memupdate для нескольких присваиваний. Например, при выделении памяти, заполненной нулями под структуру kzalloc(sizeof(*info), GFP KERNEL), mem_update выписывается только один раз после инициализации всех полей нулями.

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

memupdate.

6. Результаты

Предложенный метод был реализован в инструменте CPAchecker версии 1.4 (для экспериментов была взята ревизия 18237). За включение разработанной модели памяти на основе неинтерпретируемых функций отвечает опция cpa.predicate.handlePointerAliasing. Эксперименты проводились на наборах международных соревнований по верификации программ SV-COMP'2016 (http://sv-comp.sosv-lab.org/2016).

В первую очередь была рассмотрена категория по работе со структурами данных в куче Heap Data Structures. Задачи в этой категории требуют поддержки анализа указателей.

Запуски проводились в двух конфигурациях предикатного анализа predicateAnalysis с поддержкой модели памяти на основе неинтерпретируемых функций (с НФ) и без нее (без НФ). Как можно видеть в Таблице 4, на представленном наборе анализ с использованием предложенного метода не

133

Trudy ISP RAN [The Proceedings of ISP RAS], vol. 27, issue 5, 2015.

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

Количество вердиктов unknown составило 14 шт. для НФ, большая часть из них из-за превышения лимита по времени 10 шт. В результате общее время работы анализа с НФ составило 9514 секунд, что почти в десять раз больше чем без НФ (см. Табл. 5). Однако если рассматривать только время на корректные результаты (не включающее время на вердикты unknown), то время работы оказывается сравнимо.

Таблица 4. Результаты запуска на наборе HeapDataStructures в конфигурации предикатного анализа, с лимитом времени 15 минут и 15 Gb памяти.

Модели памяти без НФ с НФ

Общее количество 81 81

Корректные результаты 53 67

Доказано отсутствие ошибки 34 44

Ошибка найдена 19 23

Некорректные результаты 24 0

Упущенная ошибка 5 0

Ложное предупреждение 19 0

Таблица 5. Время работы CPU (в секундах) запуска на наборе HeapDataStructures в конфигурации предикатного анализа, с лимитом времени 15 минут и 15 Gb памяти.

Модели памяти без НФ с НФ

Общее время 680 9514

Время для корректных результатов 476 487

В качестве второго набора был выбран DeviceDriversLinux64, состоящий из драйверов устройств ядра операционной системы Linux, большая часть которого подготовлена в рамках проекта LDV [30, 31]. Для этого набора была

134

Труды ИСП РАН, том 27, вып. 5, 2015 г..

использована конфигурация Idv, использующаяся в проекте LDV. Видно, что время работы для этого набора сравнимо как на всех тестах, так и на тестах, для которых получен корректный результат (см. Табл. 7). Причем корректных результатов без НФ получено на 11 шт. больше (см. Табл. 6).

Таблица 8 показывает изменения вердиктов при переходе от запуска без НФ к запуску с НФ. Видно, что модель памяти с НФ теряет 31 корректный результат, из них 29 из-за вердикта unknown, одно ложное срабатывание получено из-за того, что для точной работы модели памяти с НФ в тесте не хватает явного выделения памяти, кроме того, еще в одном тесте анализ без НФ находит ложную трассу ошибки, так как считает возможным равенство нулю адреса переменной на стеке. С другой стороны, получается 20 новых корректных результатов, а 5 некорректных результатов становятся unkown.

Таблица 6. Результаты запуска на наборе DeviceDriversLinux64 в конфигурации Idv, с лимитом по времени 15 минут и 15 Gb по памяти.

Модели памяти без НФ с НФ

Общее количество 2121 2121

Корректные результаты 1654 1643

Доказано отсутствие ошибки 1450 1450

Ошибка найдена 204 193

Некорректные результаты 17 6

Упущенная ошибка 5 3

Ложное предупреждение 12 3

Таблица 7. Время работы CPU (в часах) запуска на наборе DeviceDriversLinux64 в конфигурации Idv, с лимитом по времени 15 минут и 15 Gb по памяти.

Модели памяти безНФ с НФ

Общее время 140 часов 144 часа

Время для корректных результатов 22,2 часов 22,7 часов

135

Trudy ISP RAN [The Proceedings of ISP RAS], vol. 27, issue 5, 2015.

Таблица 8. Результаты изменения вердиктов на наборе DeviceDriversLinux64 в

конфигурации Idv.

Переходы из модели памяти без НФ в модель памяти с НФ Количество

Корректный результат —> Некорректный результат 2

Корректный результат —> unknown 29

Некорректный результат — Корректный результат 8

Некорректный результат — unknown 5

Unknown — Корректный результат 12

Unknown — Некорректный результат 0

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

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

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

Литература

[1]. Edmund Clarke, Daniel Kroening, Flavio Lerda. A Tool for Checking ANSI-C Programs. In Tools and Algorithms for the Construction and Analysis of Systems (TACAS), LNCS, volume 2988, pp. 168-176,2004.

136

Труды ИСП РАН, том 27, вып. 5, 2015 г..

[2] . Armin Biere, Alessandro Cimatti, Edmund M. Clarke, Yunshan Yhu. Symbolic model

checking without BDDs. In Tools and Algorithms for Construction and Analysis of Systems, pp. 193-207, 1999.

[3] . Daniel Kroening, Edmund Clarke, Karen Yorav. Behavioral consistency of C and

Verilog programs using bounded model checking. In Proceedings of DAC 2003, pp.

368-371, ACM Press, 2003.

[4] . F. Ivancic, Z. Yang, M. K. Ganai, A. Gupta, I. Shlyakhter, P. Ashar. F-Soft: Software

Verification Platform. In CAV, LNCS, volume 3576, pp. 301-306, 2005.

[5] . H. Post, C. Sinz, F. Merz, T. Gorges, T. Kropf. Linking Functional Requirements and

Software Verification. In 17th IEEE International Requirements Engineering Conference, pp.295-302,2009.

[6] . Edmund Clarke, Oma Grumberg, Somesh Jha, Yuan Lu, Helmut Veith.

Counterexample-Guided Abstraction Refinement. In CAV, LNCS, volume 1855, pp. 154-169,2000.

[7] . М.У. Мандрыкин, B.C. Мутилин, А.В. Хорошилов. Введение в метод CEGAR —

уточнение абстракции по контрпримерам. Труды Института системного программирования РАН, том 24, стр. 219-292,2013.

[8] . S. Graf, Н. Saidi. Construction of abstract state graphs with PVS. In CAV, LNCS,

volume 1254, pp. 72-83, 1997.

[9] . Ranjit Jhala, Rupak Majumdar. Software model checking. ACM Computing Surveys,

volume 41, issue 4, article 21, pp.1-54, 2009.

[10] . William Craig. Three Uses of the Herbrand-Gentzen Theorem in Relating Model Theory

and Proof Theory. The Journal of Symbolic Logic, vol. 22, no. 3, pp. 269-285, 1957.

[11] . Roger Lyndon. An interpolation theorem in the predicate calculus. Pacific Journal of

Mathematics, vol. 9, no. 1, pp. 129-142, 1959.

[12] . Dirk Beyer, Damien Zufferey, Rupak Majumdar. CSIsat: Interpolation for LA+EUF. In

CAV, LNCS, volume 5123, pp. 304-308,2008.

[13] . Roberto Bruttomesso, Alessandro Cimatti, Anders Franzen, Alberto Griggio, Roberto

Sebastiani. The MathSAT 4 SMT Solver. In CAV, LNCS, volume 5123, pp. 299-303, 2008.

[14] . Alberto Griggio. A Practical Approach to Satisfiability Modulo Linear Integer

Arithmetic. Journal on Satisfiability, Boolean Modeling and Computation, vol. 8 pp. 1-27,2012.

[15] . Dirk Beyer, Thomas A. Henzinger, Ranjit Jhala, Rupak Majumdar. The software model

checker BLAST: Applications to software engineering. International Journal on Software Tools for Technology Transfer, volume 9, issue 5, pp. 505-525, 2007.

[16] . Швед П. E., Мутилин В. С., Мандрыкин М. У. Опыт развития инструмента

статической верификации BLAST. Программирование, том 3, стр. 24-35, 2012.

[17] . Р. Е. Shved, V. S. Mutilin, М. U. Mandrykin. Experience of improving the BLAST

static verification tool. Programming and Computer Software, volume 38, issue 3, pp. 134-142,2012.

[18] . Andersen L. O. Program Analysis and Specialization for the C Programming Language.

Kobenhavns Universitet, Datalogisk Institut, DIKU, 1994.

[19] . Marc Bemdl, Ondrej Lhotak, Feng Qian, Laurie Hendren, Navindra Umanee. Points-to

analysis using BDDs. In Proceedings of the ACM SIGPLAN 2003 conference on Programming language design and implementation, ACM, volume 38, issue 5, pp. ЮЗ-114. 2003.

137

Trudy ISP RAN [The Proceedings of ISP RAS], vol. 27, issue 5, 2015.

[20] . Pavel Shved, Mikhail Mandrykin, Vadim Mutilin. Predicate Analysis with BLAST 2.7.

In Tools and Algorithms for the Construction and Analysis of Systems, LNCS, volume 7214, pp. 525-527, 2012.

[21] . Dirk Beyer. Status Report on Software Verification (Competition Summary SV-COMP

2014). In Tools and Algorithms for the Construction and Analysis of Systems, LNCS, volume 8413, pp. 373-388, 2014.

[22] . K. Dudka, P. Peringer, T. Vojnar. Predator: A Practical Tool for Checking Manipulation

of Dynamic Data Structures Using Separation Logic. In CAV, LNCS, volume 6806, pp. 372-378,2011.

[23] . Dirk Beyer, Thomas A. Henzinger, Gregory Theoduloz. Lazy Shape Analysis. In CAV,

LNCS, volume 4144, pp. 532-546, 2006.

[24] . Tal Lev-Ami, Mooly Sagiv. TVLA: A System for Implementing Static Analyses. In

Static Analysis, LNCS, volume 1824, pp. 280-301,2000.

[25] . Dirk Beyer, M. Erkan Keremoglu, Philipp Wendler. Predicate abstraction with

adjustable-block encoding. In Proceedings of the 2010 Conference on Formal Methods in Computer-Aided Design, pp. 189-198, 2010.

[26] . Thomas A. Henzinger, Ranjit Jhala, Rupak Majumdar, Kenneth L. McMillan.

Abstractions from proofs. In Proceedings of the 31st ACM SIGPLAN-SIGACT symposium on Principles of programming languages, ACM, volume 39, issue 1, pp. 232-244,2004.

[27] . T. Bah, A. Podelski, S. K. Rajamani. Boolean and cartesian abstractions for model

checking C programs. In Tools and Algorithms for the Construction and Analysis of Systems, LNCS, volume 2031, pp. 268-283,2006.

[28] . S. K. Lahiri, R. Nieuwenhuis, A. Ohveras. SMT techniques for fast predicate

abstraction. In CAV, LNCS, volume 4144, pp. 424M37, 2006.

[29] . Dirk Beyer, Thomas A. Henzinger, Gregory Theoduloz. Configurable Software

Verification: Concretizing the Convergence of Model Checking and Program Analysis. In CAV, LNCS, 4590, pp. 504-518,2007.

[30] . M. U. Mandrykin, V. S. Mutilin, E. M. Novikov, A. V. Khoroshilov, P. E. Shved. Using

Linux Device Drivers for Static Verification Tools Benchmarking. Programming and Computer Software, volume 38, issue 5, pp. 245-256,2012.

[31] . Alexey Khoroshilov, Mikhail Mandrykin, Vadim Mutilin, Eugene Novikov, Alexander

Petrenko, Ilya Zakharov. Configurable toolset for static verification of operating systems kernel modules. Programming and Computer Software, vol. 41, n.l, pp. 49-64,2015.

138

Труды ИСП РАН, том 27, вып. 5, 2015 г..

Modeling Memory with Uninterpreted Functions for Predicate Abstractions

M.U. Mandrykin <mandrykin@ispras.ru>

V.S. Mutilin <mutilin@ispras.ru>

ISP RAS, 25 Alexander Solzhenitsyn Str., Moscow, 109004, Russian Federation

Abstract. One of the key problems in modem static verification methods is a precise model for semantics of expressions containing pointers. The trustworthiness of the verification verdict highly depends on the analysis of these expressions. In the paper we describe the verification methods with memory models based on uninterpreted functions, allowing analyzing programs containing expressions with pointers, including pointers to structures, arrays and pointer arithmetic. The approach is limited finite array size and finite recursion depth for dynamic data structures. The method is scalable, as far as it demonstrates reasonable verification times on the industrial size benchmarks containing device drivers of Linux operating system.

Keywords: memory model, predicate abstraction, counterexample-guided abstraction refinement

References

[1] . Edmund Clarke, Daniel Kroening, Flavio Lerda. A Tool for Checking ANSI-C

Programs. In Tools and Algorithms for the Construction and Analysis of Systems (TACAS), LNCS, volume 2988, pp. 168-176,2004.

[2] . Armin Biere, Alessandro Cimatti, Edmund M. Clarke, Yunshan Yhu. Symbolic model

checking without BDDs. In Tools and Algorithms for Construction and Analysis of Systems, pp. 193-207,1999.

[3] . Daniel Kroening, Edmund Clarke, Karen Yorav. Behavioral consistency of C and

Verilog programs using bounded model checking. In Proceedings of DAC 2003, pp. 368-371, ACM Press, 2003.

[4] . F. Ivancic, Z. Yang, M. K. Ganai, A. Gupta, I. Shlyakhter, P. Ashar. F-Soft: Software

Verification Platform. In CAV, LNCS, volume 3576, pp. 301-306,2005.

[5] . H. Post, C. Sinz, F. Merz, T. Gorges, T. Kropf. Linking Functional Requirements and

Software Verification. In 17th IEEE International Requirements Engineering Conference, pp.295-302,2009.

[6] . Edmund Clarke, Oma Grumberg, Somesh Jha, Yuan Lu, Helmut Veith.

Counterexample-Guided Abstraction Refinement. In CAV, LNCS, volume 1855, pp. 154-169,2000.

[7] . Khoroshilov A.V., Mandrykin M. U., MutilinV. S. Vvedenie v metod CEGAR —

utochnenie abstrakcii po kontrprimeram [Introduction to CEGAR — Counter-Example

139

Trudy ISP RAN [The Proceedings of ISP RAS], vol. 27, issue 5, 2015.

Guided Abstraction Refinement], Trudy ISP RAN [The Proceedings of ISP RAS], vol. 24, pp. 219-292, 2013 (in Russian).

[8] . S. Graf, H. Saidi. Construction of abstract state graphs with PVS. In CAV, LNCS,

volume 1254, pp. 72-83,1997.

[9] . Ranjit Jhala, Rupak Majumdar. Software model checking. ACM Computing Surveys,

volume 41, issue 4, article 21, pp.1-54,2009.

[10] . William Craig. Three Uses of the Herbrand-Gentzen Theorem in Relating Model Theory

and Proof Theory. The Journal of Symbolic Logic, vol. 22, no. 3, pp. 269-285,1957.

[11] . Roger Lyndon. An interpolation theorem in the predicate calculus. Pacific Journal of

Mathematics, vol. 9, no. l,pp. 129-142,1959.

[12] . Dirk Beyer, Damien Zufferey, Rupak Majumdar. CSIsat: Interpolation for LA+EUF. In

CAV, LNCS, volume 5123, pp. 304-308,2008.

[13] . Roberto Bruttomesso, Alessandro Cimatti, Anders Franzen, Alberto Griggio, Roberto

Sebastiani. The MathSAT 4 SMT Solver. In CAV, LNCS, volume 5123, pp. 299-303,

2008.

[14] . Alberto Griggio. A Practical Approach to Satisfiability Modulo Linear Integer

Arithmetic. Journal on Satisfiability, Boolean Modeling and Computation, vol. 8 pp. 1-

27, 2012.

[15] . Dirk Beyer, Thomas A. Henzinger, Ranjit Jhala, Rupak Majumdar. The software model

checker BLAST: Applications to software engineering. International Journal on Software Tools for Technology Transfer, volume 9, issue 5, pp. 505-525,2007.

[16] . P. E. Shved, V. S. Mutilin, M. U. Mandrykin. Opyt razvitiya instrumenta staticheskoy

verifikatsii BLAST. [Experience of improving the BLAST static verification tool]. Programmirovanie [Programming and Computer Software], vol. 38, issue 3, pp. 25-34, 2012 (in Russian).

[17] . P. E. Shved, V. S. Mutilin, M. U. Mandrykin. Experience of improving the BLAST

static verification tool. Programming and Computer Software, volume 38, issue 3, pp. 134-142,2012.

[18] . Andersen L. O. Program Analysis and Specialization for the C Programming Language.

Kobenhavns Universitet, Datalogisk Institut, DIKU, 1994.

[19] . Marc Bemdl, Ondrej Lhotak, Feng Qian, Laurie Hendren, Navindra Umanee. Points-to

analysis using BDDs. In Proceedings of the ACM SIGPLAN 2003 conference on Programming language design and implementation, ACM, volume 38, issue 5, pp. 103-114.2003.

[20] . Pavel Shved, Mikhail Mandrykin, Vadim Mutilin. Predicate Analysis with BLAST 2.7.

In Tools and Algorithms for the Construction and Analysis of Systems, LNCS, volume 7214, pp. 525-527,2012.

[21] . Dirk Beyer. Status Report on Software Verification (Competition Summary SV-COMP

2014). In Tools and Algorithms for the Construction and Analysis of Systems, LNCS, volume 8413, pp. 373-388,2014.

[22] . K. Dudka, P. Peringer, T. Vojnar. Predator: A Practical Tool for Checking Manipulation

of Dynamic Data Structures Using Separation Logic. In CAV, LNCS, volume 6806, pp. 372-378,2011.

[23] . Dirk Beyer, Thomas A. Henzinger, Gregory Theoduloz. Lazy Shape Analysis. In CAV,

LNCS, volume 4144, pp. 532-546, 2006.

[24] . Tal Lev-Ami, Mooly Sagiv. TVLA: A System for Implementing Static Analyses. In

Static Analysis, LNCS, volume 1824, pp. 280-301,2000.

140

Труды ИСП РАН, том 27, вып. 5, 2015 г..

[25] . Dirk Beyer, М. Erkan Keremoglu, Philipp Wendler. Predicate abstraction with

adjustable-block encoding. In Proceedings of the 2010 Conference on Formal Methods in Computer-Aided Design, pp. 189-198,2010.

[26] . Thomas A. Henzinger, Ranjit Jhala, Rupak Majumdar, Kenneth L. McMillan.

Abstractions from proofs. In Proceedings of the 31st ACM SIGPLAN-SIGACT symposium on Principles of programming languages, ACM, volume 39, issue 1, pp. 232-244,2004.

[27] . T. Ball, A. Podelski, S. K. Rajamani. Boolean and cartesian abstractions for model

checking C programs. In Tools and Algorithms for the Construction and Analysis of Systems, LNCS, volume 2031, pp. 268-283,2006.

[28] . S. K. Lahiri, R. Nieuwenhuis, A. Oliveras. SMT techniques for fast predicate

abstraction. In CAV, LNCS, volume 4144, pp. 424-437,2006.

[29] . Dirk Beyer, Thomas A. Henzinger, Gregory Theoduloz. Configurable Software

Verification: Concretizing the Convergence of Model Checking and Program Analysis. In CAV, LNCS, 4590, pp. 504-518,2007.

[30] . M. U. Mandrykin, V. S. Mutilin, E. M. Novikov, A. V. Khoroshilov, P. E. Shved. Using

Linux Device Drivers for Static Verification Tools Benchmarking. Programming and Computer Software, volume 38, issue 5, pp. 245-256,2012.

[31] . Alexey Khoroshilov, Mikhail Mandrykin, Vadim Mutilin, Eugene Novikov, Alexander

Petrenko, Ilya Zakharov. Configurable toolset for static verification of operating systems kernel modules. Programming and Computer Software, vol. 41, n.l, pp. 49-64,2015.

141