Научная статья на тему 'Учет модели памяти в алгоритме поиска утечек ресурсов в программах на языке C'

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

CC BY
142
30
i Надоели баннеры? Вы всегда можете отключить рекламу.
Ключевые слова
СТАТИЧЕСКИЙ АНАЛИЗ (STATIC ANALYSIS) / МОДЕЛЬ ПАМЯТИ (MEMORY MODEL) / УКАЗАТЕЛЬ (POINTER) / ПОИСК УТЕЧЕК (LEAKS SEARCH)

Аннотация научной статьи по компьютерным и информационным наукам, автор научной работы — Исаев Денис Сергеевич, Ломовской Игорь Владимирович

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

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

Похожие темы научных работ по компьютерным и информационным наукам , автор научной работы — Исаев Денис Сергеевич, Ломовской Игорь Владимирович

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

Текст научной работы на тему «Учет модели памяти в алгоритме поиска утечек ресурсов в программах на языке C»

6. ФорресторД. Мировая динамика. М.: ACT, 2003. 379 c.

7. Харман Г. Современный факторный анализ. М.: Статистика, 1972. 486 с.

8. Черненький В. М., Терехов В. И., Гапанюк Ю. Е. Структура гибридной интеллектуальной информационной системы на основе метаграфов, 2005. 23 с.

9. MedskerL. R. Hybrid Intelligent Systems. Boston: Kluwer Academic Publishers, 1995. 298 p.

Учет модели памяти в алгоритме поиска утечек ресурсов в программах

на языке C Исаев Д. С.1, Ломовской И. В.2

'Исаев Денис Сергеевич /Isaev Denis Sergeevich — бакалавр техники и технологий;

2Ломовской Игорь Владимирович /Lomovskoy Igor Vladimirovich — старший преподаватель, кафедра программного обеспечения ЭВМ и информационных технологий, Московский государственный технический университет им. Н. Э. Баумана, г. Москва

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

Ключевые слова: статический анализ (static analysis), модель памяти (memory model), указатель (pointer), поиск утечек (leaks search).

Введение

В работе [1] описан подход к поиску утечек ресурсов в программах на языке C: выполняется статический анализ кода, и из графа потока управления создается граф состояний программы. Утечка считается обнаруженной, если в конечных вершинах графа состояний есть неосвобожденные ресурсы.

Использование данного подхода на практике показало его ограниченность при анализе программ, в которых указатели используются для косвенного обращения к переменным. Это вызвано тем, что в работе [1] используется нереалистичная модель памяти программы. В настоящей работе это ограничение снято.

Анализ использованной ранее модели памяти

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

Операции разыменования и взятия адреса переменной никак не анализировались в алгоритме поиска утечек из указанной работы. Это может приводить как к ложноположительным, так и к ложноотрицательным срабатываниям алгоритма при работе с указателями. Например, если функции нужно изменить значение указателя, который передается в эту функцию в качестве одного из ее параметров. В работе [1] такой случай будет считаться утечкой, то есть будет ложноположительное срабатывание.

Обзор моделей памяти, лишенных рассмотренных недостатков

Существуют следующие способы организации памяти, применяемые в статическом анализе [2] :

а) связывание имен переменных со значениями;

б) представление памяти в виде массива;

в) представление памяти в виде регионов;

г) прочие модели памяти.

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

Модификация модели памяти в виде регионов

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

Введем термины символа и символьного значения. Символ - это любое выражение в исходном коде. Символьное значение - значение, которое принимает это выражение при выполнении программы, то есть r-value [3] выражения.

Когда анализатор работает с каким-либо выражением (например, с переменной), он может получить его l-value [3] и r-value. L-value выражения представляет собой его регион памяти, который создается при первом обращении к выражению в анализаторе. R-value выражения - это символьное значение, хранящееся в данном регионе. Заметим, что r-value указателя это регион памяти, на который он указывает. В таблице 1 приведена иллюстрация рассмотренных понятий на примере из листинга 1.

int a = 5; int *pa = &a;

Листинг 1. Пример для иллюстрации рассмотренных понятий

Таблица 1. Иллюстрация вышеизложенных понятий на примере из листинга 1

Символ Символьное значение (r-value) Регион (l-value)

A 5 R1

&a R1 R2 (временный регион)

Pa R1 R3

*pa 5 R1

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

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

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

Недостатком данной модели памяти является отсутствие поддержки массивов и структур.

Доработка алгоритма поиска утечек ресурсов

Алгоритм поиска утечек ресурсов [1] состоит из множества более мелких алгоритмов: алгоритма анализа выражений, алгоритма конструирования графа состояний, алгоритм отслеживания состояния данных и др. Для поддержки предложенной модели памяти требуется доработать некоторые из этих алгоритмов.

Перед тем, как описывать изменения в этих алгоритмах введем термины «потерянного» символьного значения и региона.

Регион разрушается и считается «потерянным», если он больше не используется в программе. Например, при выходе из функции регионы на стеке, в которых располагались локальные переменные функции, разрушаются. Это соответствует организации памяти при выполнении программы: в функции локальные переменные выделяются на стеке, а при выходе из функции указатель стека сдвигается, и эту стековую память больше нельзя использовать.

Когда на регион теряется ссылка, он тоже считается «потерянным». Например, в выражении (void) malloc(16) «потерян» регион размером 16 байт, выделенный вызовом malloc, так как возвращаемое функцией malloc значение игнорируется.

«Потерянным» символьным значением считается символьное значение, расположенное в «потерянном» регионе.

Доработка алгоритма вычисления символьного значения выражения

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

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

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

def get symbol_valiie of expression(expr, state):

deref_svat = state.build svat from gcc_var(expr.operand) raise Error!'Dereference of non-pointer")

svat = state.get region manager().get region value(region) state.get_region_manager().set_region_value(region, svat)

return state.get_region_manager().get_region_value(region)

Листинг 2. Псевдокод алгоритма вычисления символьного значения выражения

Доработка алгоритма анализа выражений вида «присваивание»

Выражения вида «присваивание» представляют собой выражения вида lhs = rhs.

Алгоритм анализа выражений вида «присваивание» был модифицирован аналогично алгоритму вычисления символьного значения. В листинге 2 показан псевдокод части алгоритма, в которой определяется «потеряно» ли предыдущее символьное значение (rewrittensval) левой стороны присваивания (lhs).

На вход алгоритму поступают левая (lhs) и правая (rhs) стороны присваивания. На выходе алгоритм формирует пару из предыдущего символьного значения левой части присваивания (rewritten sval) и флага потерянности этого значения (isdead). Основной доработкой для данного алгоритма является показанная в листинге 3 проверка «потерянности» (is dead == True если значение «потеряно»). Символьное значение считается «потерянным», если его нет больше ни в одном из регионов.

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

def process.assignment(lhs, rhs, state):

if rewritten_sval is not None:

regions = state.get_region_manager().\ get_regions_with_svalue(rewritten_sval)

return {rewritten_sval, is_dead)

Листинг 3. Псевдокод части алгоритма анализа выражений вида «присваивание»

Доработка алгоритма обнаружения «незначительных» функций

«Незначительные» функции не анализируется для уменьшения времени выполнения анализа, так как они не влияют на работу программы. Было сделано следующее изменение: если функция

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

Разработка алгоритма проверки «потерянного» указателя

В работе [1], если обнаружено «потерянное» значение, то оно передается конкретным анализаторам для обработки. В данной работе был добавлен алгоритм дополнительной проверки «потерянного» значения.

Если «потерянное» значение является указателем, то алгоритм пытается найти «потерянное» значение, на которые этот указатель может ссылаться. Это позволяет обнаруживать больше утечек, то есть совершать меньше ложноотрицательных срабатываний.

Алгоритм заключается в следующем: символьное значение, на которое ссылается «потерянный» указатель считается «потерянным», если выполнены все условия:

а) регион, на который ссылается указатель существует;

б) регион, на который ссылается указатель не является регионом на стеке (указатель может указывать на переменные выше по стеку);

в) не существует других указателей, ссылающихся на данный регион.

Далее для «потерянного» символьного значения рекурсивно выполняется вышеописанный алгоритм, если оно тоже является указателем.

Доработка реализации алгоритма

В процессе поддержки более реалистичной модели памяти была добавлена поддержка обнаружения утечек для следующих видов ресурсов:

а) Динамическая память, выделенная с помощью malloc.

б) Файловый дескриптор, выделенный с помощью open.

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

Исследование анализатора на работах студентов

Все исследования проводились в операционной системе Ubuntu 14.04 с компилятором gcc 4.8.2. Операционная система была запущена в виртуальной машине, которой было выделено 3 Гбайт оперативной памяти и одно ядро процессора Inter Core i5 с частотой 2.4 ГГц.

Для исследования разработанного анализатора на работах студентов были автоматизированно загружены лабораторные работы 85 студентов по предмету «Программирование на Си». Загруженные работы содержали 2149 файлов исходного кода на языке C.

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

Общее время выполнения анализа всех 2149 файлов исходного кода составило 11 минут 9 секунд. Было успешно проанализировано 1848 файлов (85.9%), остальные файлы не удалось проанализировать из-за ошибок компиляции. Ошибки компиляции вызваны различными причинами, например, опечатками.

Сравнение анализатора с существующими статическими анализаторами

В данном разделе производится сравнение разработанного анализатора (далее он обозначается как gsa) с существующими статическими анализаторами кода clang sa [4] и cppcheck [5].

Сравнение производится по следующим параметрам:

а) Максимальный объем резидентной памяти процесса анализатора во время выполнения. Под резидентной памятью процесса понимаются страницы памяти, находящиеся в оперативной памяти, а не сброшенные на диск. Для получения значения данного параметра используется программа time [6]. В качестве параметра используется максимальный, а не средний объем резидентной памяти, т.к. операционная система Ubuntu не позволяет определять усредненный объем резидентной памяти средствами программы time.

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

в) Количество правильно найденных утечек ресурсов (динамическая память, файловый поток или файловый дескриптор).

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

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

51

Для сравнения данных параметров производился запуск анализаторов на 1848 файлах.

Результаты сравнения

Разработанный анализатор (GSA) обнаружил утечки в 282 файлах, анализатор clang - в 385 файлах, анализатор cppcheck - в 227 файлах.

Утечки, найденные всеми анализаторами, расположены в 504 файлах (27.2% от общего количества проанализированных файлов). Исключим из этих файлов те, в которых утечки были найдены всеми анализаторами (таких файлов 131). Среди оставшихся 373 файлов случайно выберем 50. Для получения точного числа правильно найденных утечек и ложноположительных срабатываний анализаторов изучим именно эти файлы.

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

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

Таблица 2. Число положительных и ложноположительных срабатываний анализаторов

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

Анализатор Кол-во правильно найденных утечек Кол-во неправильно найденных утечек Кол-во уникальных правильно найденных утечек

Clang SA 209 176 39

GSA 196 86 33

Cppcheck 199 28 0

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

Таблица 3. Максимальный объем резидентной памяти анализаторов

Анализатор Максимальный объем резидентной памяти (среднее), Мб Максимальный объем резидентной памяти (медиана), Мб

Clang SA 15.8 13.3

GSA 102.7 68.4

Cppcheck 2.7 2.7

Разработанный анализатор потребляет памяти больше, чем у остальные анализаторы. Это вызвано большим потреблением памяти самим компилятором gcc и использованием языка Python, использующего сборщик мусора, который освобождает память лишь в определенные моменты времени. В то время как cppcheck и clang sa написаны на языке C++ и не используют сборщик мусора.

Результаты сравнения анализаторов по времени выполнения анализа приведены в таблице 4.

Таблица 4. Время выполнения анализа

Анализатор Время выполнения анализа (среднее), с Время выполнения анализа (медиана), с

Clang SA 0.3 0.2

GSA 0.7 0.4

Cppcheck 0.01 0.01

Для ускорения работы разработанного анализатора были проведены технические и алгоритмические улучшения, позволившие уменьшить потребление памяти на 10%, среднее время анализа в 29 раз, медианное время анализа в 19 раз по сравнению с предыдущей версий анализатора. Тем не менее, разработанный анализатор работает в среднем на 57% медленнее, чем анализатор clang и на 99% медленнее, чем анализатор cppcheck.

Найденные ошибочные срабатывания

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

void test_apply_filter() {

int* arr_4 = (int*)malloc(size*sizeof(int)); apply_filter(&arr_4, &size);

}

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

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

По итогам проделанной работы были достигнуты следующие результаты:

а) Рассмотрен алгоритм поиска утечек ресурсов из работы [1], показан его недостаток при работе с указателями. Разработана модель памяти для устранения данного недостатка. Доработан и реализован алгоритм поиска утечек ресурсов для учета разработанной модели памяти.

б) Добавлена поддержка поиска утечек для файловых дескрипторов и динамической памяти.

в) Скорость работы анализатора была значительно увеличена. Тем не менее, разработанный анализатор работает в среднем на 57% медленнее, чем анализатор clang и на 99% медленнее, чем анализатор cppcheck.

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

Литература

1. Исаев Д. С., Ломовской И. В. Разработка алгоритма поиска утечек ресурсов в программах на языке C. [Электронный ресурс]: Молодежный научно-технический вестник. URL: http://sntbul.bmstu.ru/doc/746265.html (дата обращения: 09.05.2016).

2. Чонгхинг Ху. A Memory Model for Static Analysis of C Programs. [Электронный ресурс]: Персональный веб-сайт. URL: http://lcs.ios.ac.cn/~xzx/memmodel.pdf. (дата обращения: 09.05.2016).

3. l-values and r-values. [Электронный ресурс]: Wikipedia. URL: https://en.wikipedia.org/wiki/Value_(computer_science) - lrvalue (дата обращения: 09.05.2016).

4. Clang Static Analyzer. [Электронный ресурс]: Clang Static Analyzer. URL: http://clang-analyzer.llvm.org/ (дата обращения: 9.05.2016).

5. Cppcheck. A tool for static C/C++ code analysis. [Электронный ресурс]: Cppcheck. URL: http://cppcheck.sourceforge.net. (дата обращения: 09.05.2016).

6. time(1). [Электронный ресурс]: Linux man page. URL: http://linux.die.net/man/1/time (дата обращения: 09.05.2016).

Проблема согласования линий передач в СВЧ диапазоне Петухова Н. А.

Петухова Наталья Александровна / Petukhova Natalya Aleksandrovna - аспирант, магистр, Санкт-Петербургский национальный исследовательский университет информационных технологий, механики и оптики, г. Санкт-Петербург

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

Радиосистемы, работающие в диапазоне от 30 МГц дл 300 ГГц, обычно можно представить в виде устройств, соединенных отрезками линии передачи. Часть такой системы, расположенную между

53

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