Автоматическое обнаружение дефектов в многопоточных программах методами статического анализа

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

Использование языка Java и технологии J2EE

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

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

СПИСОК ЛИТЕРАТУРЫ

1. Chaum, D. Group signatures [Текст] / D. Chaum, E. van Heyst // Proc. of Eurocrypt 1991. -Springer-Verlag, Apr. 1991. -P. 257-265.

2. Организация Trusted Computing Group [Электронный ресурс] www.trustedcomputinggroup.org

3. Shacham, H. Collected Papers where Every Theorem Is Filled with Grief. Dec. 2005 [Электронный ресурс]/Н. Shacham//http:// cseweb.ucsd.edu/~hovav/dist/ thesis-hyperref.pdf

4. Ateniese, G. Quasi-Efficient Revocation of Group Signatures [Электронный ресурс] / G. Ateniese, D. Song, G. Tsudik // http: www.cs.jhu.edu/~ateniese/papers/fc02.pdf

5. Ateniese, G. A Practical and Provably Secure Coalition-Resistant Group Signature Scheme [Электронный ресурс] / G. Ateniese, J. Camenisch, M. Joye [et al.] // Advances in Cryptology-CRYPTO 2000. -Springer Verlag, 2000. -LNCS. -Vol. 1880. -P. 255-270.

http://www.zurich.ibm.com/~jca/papers/ group2000.pdf

6. Yao, D. Cascaded Authorization with Anonymous-Signer Aggregate Signatures [Электронный ресурс] /D. Yao, R. Tamassia//Proc. of the 7 Annual IEEE Systems, Man and Cybernetics Information Assurance Workshop (IAW '06). - United States Military Academy, West Point, NY. - June 2006. http://www.cs.brown.edu/cgc/stms/ papers /anonymity.pdf

7. Библиотека NuimCrypto [Электронный ресурс] http://www.google.com.my/codesearch/ p?hl=en&sa= N%20&cd=1&ct=rc#vE_ES1OPacI/software/&q=http:// www.crypto.cs.nuim.ie/

8. MIRACL, Multiprecision Integer and Rational Arithmetic C/C++ Library [Электронный ресурс] http:// www. shamus.ie/

9. The Pairing-Based Cryptography Library [Электронный ресурс] http://crypto.stanford.edu/pbc/

УДК 004.052.42

М.Ю. Моисеев

АВТОМАТИЧЕСКОЕ ОБНАРУЖЕНИЕ ДЕФЕКТОВ В МНОГОПОТОЧНЫХ ПРОГРАММАХ МЕТОДАМИ СТАТИЧЕСКОГО АНАЛИЗА

Статический анализ (СА) - группа методов, использующих исходный код программы для определения требуемых свойств [1]. Одной из областей применения СА является обнаружение

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

ных программах на языке C являются: разыменование некорректного указателя, переполнение буфера и выход за границы объекта, использование неинициализированных переменных, утечки и повторное освобождение ресурсов. Методы СА позволяют автоматически обнаруживать дефекты всех указанных типов. Основными показателями эффективности статического анализа являются полнота и точность получаемых результатов. Полнота - доля обнаруженных дефектов среди всех дефектов, имеющихся в программе. Точность - доля истинных дефектов среди всех обнаруженных дефектов.

В настоящее время существуют эффективные алгоритмы СА, позволяющие выполнять обнаружение дефектов. Однако большинство известных алгоритмов и их реализации ориентированы на анализ последовательных программ, в то время как многие из существующих и разрабатываемых программных систем используют те или иные механизмы распараллеливания. Одним из классов параллельных программ являются многопоточные программы. В них кроме дефектов последовательных программ могут присутствовать дефекты, связанные с организацией параллельного выполнения -ошибки синхронизации. К таким дефектам относятся: конкурентная модификация/использование разделяемых объектов из разных потоков (Race Condition), взаимные блокировки (Deadlock), некорректное использование функций синхронизации (Blocking Call Misuse) и др. Применение алгоритмов СА, не учитывающих специфику многопоточных программ, не позволяет обнаруживать ошибки синхронизации, а также приводит к снижению полноты и точности получаемых результатов.

В данной статье решается задача автоматического обнаружения дефектов последовательных программ в многопоточных программах на языке C на основе методов СА. Основным требованием к разрабатываемым алгоритмам является получение полных результатов. В качестве примера рассматривается организация многопоточных программ на основе потоков и объектов синхронизации определенных в стандарте POSIX (IEEE 1003.1).

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

ций; применяется анализ наборов конструкций синхронизации на путях выполнения программы (lockset-анализ); используются системы типов и эффектов.

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

К подходам на основе lockset-анализа относится работа [4], в которой предлагается простой алгоритм обнаружения ошибок типа Deadlock и Race Condition. Этот алгоритм использует подсчет числа выполненных операций захвата и освобождения объектов синхронизации на всех путях в графе потока управления до некоторой точки программы. В [5] решается задача определения достижимости совместного состояния параллельных потоков, для программ с рекурсией. Предлагается общий подход построения lockset-алгоритмов, рассматриваются алгоритмы First Occurrence ordering, Label bitvector, Forbidden and Required sets и Parikh images.

Одним из представителей подходов на основе системы типов является работа [6]. С помощью системы типов строится набор ограничений, позволяющий определить обращения к объектам многопоточной программы без использования объектов синхронизации - такие обращения считаются ошибками типа Race Condition.

Оригинальный подход предлагается в [7] -анализ потоков многопоточной программы заменяется на анализ путей в последовательной программе. Для этого исходная многопоточная программа преобразуется в эквивалентную последовательную программу. Эмуляция недетерминизма выполнения параллельных потоков осуществляется с помощью добавления специальных конструкций.

Существует ряд работ, в которых рассматриваются вопросы обнаружения дефектов последо-

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

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

Статический анализ последовательных программ

Задачу обнаружения программных дефектов методами СА можно разделить на три стадии: формирование модели программы; извлечение необходимой информации из построенной модели;

обнаружение дефектов на основе полученной информации.

Модель программы является упрощенным представлением исходного кода программы и содержит информацию только о тех объектах и конструкциях, которые интерпретируются алгоритмами анализа. В качестве модели программы для СА наиболее часто используются: синтаксическое дерево разбора (Abstract Syntax Tree), абстрактный семантический граф (Abstract Semantic Graph), граф потока управления (Control Flow Graph), модель программы со статическим однократным присваиванием (Single Static Assignment) [9].

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

выполнения программы и объединение состояний программы в местах слияния потоков управления (первый вариант обладает высокой вычислительной сложность и поэтому имеет ограниченное применение).

При определении состояний программы обычно выделяют интервальный анализ, анализ указателей и ресурсный анализ. Интервальный анализ определяет значения переменных простых типов. Анализ указателей определяет объекты, на которые указывают переменные-указатели. Ресурсный анализ определяет состояния ресурсов (файлов, сокетов и т. п.). Будем называть алгоритмы интервального анализа, анализа указателей и ресурсного анализа основными алгоритмами.

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

Основная идея предлагаемого подхода

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

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

Модель многопоточной программы

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

Рассмотрим пару базовых блоков БЦ и которые выполняются в разных потоках программы. Блоки Б' и Б'2 являются совместными, если

г1 г2 '

существует набор входных данных, на котором выполняются оба этих блока.

Конструкции синхронизации взаимодействуют друг с другом с помощью блокировки и освобождения объекта синхронизации - представим взаимодействие между парами конструкций синхронизации с помощью отношений синхронизации. Для конструкций синхронизации 51 (после блока Б'1) и s2 (после блока Б^) имеет место отношение синхронизации, если блоки Б'1, Б' совместны и существует набор входных данных, на котором выполнение 51 обеспечивается выполнением s . Обозначим отношение синхронизации между такими конструкциями - Б' ^ Бл+Г

Между блоками Б7'1 и Б' существует строгая последовательность выполнения, если на всех наборах входных данных сначала выполняется блок БД затем блок Б' или наоборот. Строгая последовательность выполнения блоков организуется с помощью взаимодействий между конструкциями синхронизации.

Базовые блоки, выполняющиеся в разных потоках программы, могут выполняться параллельно, если эти блоки являются совместными и отсутствует строгая последовательность их выполнения. Обозначим отношение параллельности между блоками Б л, Б' - Б' || Б '2. Отношение г1 г2 г1 г2

параллельности - коммутативное и не является транзитивным:

г1 г2 г2 м г^ г1 м г^ г1 11 гз г2 11 гз

Конструкции синхронизации выполняются над объектами синхронизации. Изменяя состояние этих объектов, можно выделить два вида объектов синхронизации:

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

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

Среди объектов синхронизации, определенных в стандарте POSIX, с помощью объектов первой группы представляются объекты типа pthread_mutex_t, pthread_rwlock_t, pthread_spinlock_t, pthread_once_t, с помощью объектов второй группы - объекты типа sem_t, pthread_barrier_t, с помощью объектов обеих групп - объекты типа pthread_ cond_t. В рамках данной статьи ограничимся рассмотрением объектов типа pthread_mutex_t (в нерекурсивном режиме) и объектов типа sem_t.

Изменение состояния объекта в конструкциях синхронизации назовем действием над этим объектом. Для объекта синхронизации первой группы возможны два действия - блокировка (LOCK) и снятие блокировки (UNLOCK). Для объекта синхронизации второй группы действие представляется целым числом с диапазоном значений (-да, +да). Отрицательные значения соответствуют операциям блокировки объекта, положительные -операциям снятия блокировки, нулевое значение - отсутствию влияния на объект синхронизации.

Состояние объекта синхронизации влияет на результат выполнения конструкций синхронизации. Объект синхронизации первой группы может иметь два состояния - заблокирован (LOCKED) и не заблокирован (UNLOCKED). Состояние объекта синхронизации второй группы - целое число с диапазоном значений [0, +да). Значение равное нулю соответствует состоянию блокировки объекта синхронизации, положительные значения -состояниям отсутствия блокировки.

Модель многопоточной программы представляет собой модель последовательной программы, дополненную объектами и конструкциями синхронизации. В качестве модели последовательной программы используется модифицированная модель со статическим однократным присваиванием [10]. Дополнительными объектами являются объекты-потоки программы и объекты синхронизации двух видов. Конструкции синхронизации представляют типичные функции, выполняемые над этими объектами:

create(t, pf) - создание потока программы и запуск в нем функции, на которую указывает переменная pf;

join(t) - ожидание завершения потока программы;

init(m, value) - инициализация объекта синхронизации, на который указывает переменная m, действие данной конструкции равно value;

destroy(m) - уничтожение объекта синхронизации;

lock(m) - блокировка объекта синхронизации первой группы, действие данной конструкции равно LOCK;

wait(m, dec) - блокировка объекта синхронизации второй группы, действие данной конструкции равно dec;

unlock(m) - освобождение объекта синхронизации первой группы, действие данной конструкции равно UNLOCK;

post(m, inc) - освобождение объекта синхронизации второй группы, действие данной конструкции равно inc;

state(m) - определение состояния объекта синхронизации;

eot - последняя конструкция потока программы.

Представление основных функций над потоками и выбранными объектами синхронизации стандарта POSIX с помощью конструкций синхронизации приведено в таблице.

Функции pthread_mutex_trylock и pthread_trywait, а также ряд других функций, определенных в POSIX выполняются атомарно. Корректность представления атомарных функций с помощью нескольких конструкций, а также способы представления остальных функций остаются за рамками данной статьи.

Алгоритм анализа потоков программы

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

Исходная функция Представление с помощью конструкций синхронизации

pthread_create

pthread_join

pthread_mutex_init

pthread_mutex_unlock

pthread_mutex_lock

pthread_mutex_trylock(m) if (state(m) == LOCKED) { return false; } else { lock(m); return true;

sem_init

sem_post

sem_wait

sem_getvalue

pthread_trywait(m) if (state(m) == 0) { return false; } else { wait(m, 1); return true;

зации выполняется на основе анализа действии над этим объектом во всех потоках программы. Обозначим возможные состояния объекта m в базовом блоке Sj - m(Sj). Для определения m(Sj) строятся комбинации блоков других потоков, параллельно с которыми может выполняться блок Sj. Назовем все такие комбинации для блока Sj -множеством допустимых комбинаций, {C}SJ.

Множество допустимых комбинаций строится из блоков, которые могут быть параллельны блоку Sj; в каждую комбинацию входит по одному блоку из каждого потока; все блоки комбинации должны быть попарно параллельны:

VC е fe1 : S/1 11 S( }: VS/2, S* e С St 11S/3 Ce{C%

Действия над объектами синхронизации рассматриваются отдельно для каждого потока программы. Назывем множеством действий над объектом синхронизации в базовом блоке действия над этим объектом на всех путях от первой конструкции потока до данного блока. Обозначим множество действий над объектом m в базовом блоке Sj - ^(m, Sj). Правила влияния конструкций программы на множество действий выглядят следующим образом (обозначения блоков приведены на рис. 1):

lifOS/jelseS* ]: А(т,5/') = л(т, S/1}л(т, S/1) = а(ш,S?')' N1 = Ф^ .Si)]: Arn,S>; )= )и A{m,S>>)'

[create(t, pf)]: л(т, S*+1) = л{т, S*), A(m, S/2) = {UNLOCK} I {o}' [join{t)]:A{m,S*+l)= A{m,S*)+ A(m,5f)'

[lock{m)\: A{m, S£+1) = {LOCK}'

[unlock(m)]: a(m, st+1)={unlock}'

[wait(m, dec)]: A[m, 5Д,) = A(m, )+dec' [post(m,inc)]: A(m, S/*+1) = л(т, S/*)+ inc

Множество действий в первой конструкции потока равно {UNLOCK} для объектов первой группы и {0} для объектов второй группы. Результат операции сложения множеств действий представляет собой все возможные суммы из действий каждого множества:

A(m,S^)={al,...al,...a2Ni\ А(т,5*)+ +а\} Vi, =

= l...Nl,i2=l...N2.

Состояния объектов синхронизации второй группы определяются с помощью следующего правила:

VC6 {с%,

[state{m)]: m{sjj) = m(s/j )U

VS/eC

Начальное значение состояния т^1) - пустое множество.

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

Рис. 1. Обозначения блоков программы

3С е {с'}хл : 35/ е С U S£, {ЬОСК}е а(гп, S)) [siafe(m)]: m(s/' )= т [s!;){] {LOCKED}

3С е {C'}s, : VS/ е С U S/1, {£/2VL0CX)e А(т, S'j ) [state(m)]: m(s(1) = m(s* ){J {UNLOCKED}

Правила построения отношений параллельности выглядят так:

VS/: S/ IIS/

\if () St else St 1: S/1 II S/,S/' IIS/' '

Ы V {j Jg J J2 | » Jj i

VS/ :S/1 IIS/vS/1 IIS/

VS/:S/4IS/

[creaie(i,p/)]: II S/%S^ II S/,S/2 IIS/ ' VC: Ce {C% , S/2 e C,S/ e С [/ofn(i)]:S^! IIS/ ' VS/' e С: С e {С}хл , 3S/'S 6 С A(w, S/'s )={LOCK} [lock{mj\:S»+1\\S/ '

VS/ : S/2 IIS/ 1 ^ 1

[Mnfodc(m)]:S/2+1 IIS/''

VS/'e С:Се{С'}хл,Эае A(m,S/')+ ,а> 0

VS/'EC

[wait(m)]: S£+111S/

VS/ : S/2 IIS/

_1 h 1

[post(m)]:S£+1 IIS/

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

Правила построения отношений синхронизации имеют вид:

[create{t,pf)]:S* ->S/2 '

- Я/Ч IS/2

h h

[join(t)]:Sg S* ' [<lock(m)]: S* S * '

ЗС:Се{С%,Зае A(m,S/')+ 2>(m,S/) , а = 0, S/2 е С

VS/eC

V1

[wait{m)\.St —» S/ Отношение синхронизации для пары конструкций wait/post строится в случае, если в комбинации для блока перед конструкцией wait объект синхронизации может изменить свое состояние после выполнении конструкции post.

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

На рис. 2 приведен пример программы, в которой используется объект синхронизации первой группы. Рассмотрим работу предложенного алгоритма для блоков потока 1, считая, что остальные

)---Кло)

{UNLOCK} С-2 {UNLOCK С3

Ick ) ( Ick

{UNLOCK}

{LOCK}

{LOCK}

Рис. 2. Пример работы алгоритма анализа потоков программы

потоки программы уже проанализированы. Блок Sj может выполняться параллельно с блоками: S 3, S 4, S1, S 2, S 3. Между этими блоками имеют место следующие отношения параллельности: S 3 || S 3, S 3, S 4 || S 3, S 3, S 3. Множество допустимых комбинаций (С'}„ 1. включает следующие комбинации:

(S33, s?),( s3 , s 33),( s 43, s?),( s 43, s 3), ( S 43, S33). Состояние объекта синхронизации

m(S 1) = [LOCKED, UNLOCKED}. Правилу построения отношений параллельности для конструкции lock удовлетворяют комбинации {s 43, Sj (S 43, S33 ^, - блок S3 может выполняться параллельно с S 4, S J, S 3. Так как Sj || S 3, S 3, то для конструкции lock строятся две дуги синхронизации: s 3 ^ S3, s 3 ^ S3.

Взаимодействие потоков программы

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

Добавление ^-функций осуществляется для конструкций create, join, lock и wait. Каждая ^-функция имеет один вход из текущего потока (кроме ^-функции для конструкции create) и один или несколько входов из других потоков. Входы в ^-функцию из других потоков строятся на основе дуг синхронизации - для каждой входящей дуги синхронизации добавляется один вход в ^-функцию.

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

Для определения актуального значения необходимо фиксировать изменения значений разделяемых объектов в базовых блоках програм-

мы. Обозначим значение разделяемого объекта e в блоке Sj - e(Sj), а изменение этого значения в данном блоке - def(e) G Sj. Определение актуального значения для ^-функции с двумя входами выполняется по следующим правилам (обозначения блоков приведены на рис. 3):

3S/2 :S/1 11 S/2,S/2 s Pred{s£ ), def{e)s S/2 as/1 : S/2 11 Si1, Si1 e Pr ed(s* \ def{e)e S/1 as/: S/1 11 S/, def(e)e S/

^SRsJ] '

3S/:S;f IIS/,^/(e)eS/

Pr ed

- множество блоков j-го потока, выполнение которых предшествует выполнению блока SJ; блок SJ также входит в Pr ed(Sj).

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

S/' , - -

С Л

ЛГ

Рис. 3. Обозначения блоков для у-функции

Обнаружение дефектов

В данной статье решается задача обнаружения дефектов последовательных программ. Алгоритм анализа потоков рассчитан на применение для программ, в которых отсутствуют (обнаружены) ошибки типа Blocking Call Misuse (правила для конструкций join и lock) и Race Condition (правила определения актуального состояния). Поэтому, наряду с обнаружением программных дефектов последовательных программ, также необходимо обнаруживать ошибки синхронизации этих типов.

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

К ошибкам типа Blocking Call Misuse относятся: отсутствие освобождения заблокированного

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

Зт: {ЮСК}е А(Ш, SJ ) \eot\: Defect

{ЬОСК}е А(т, Sj ) [lock(m)]: Defect '

{UNLOCK}e [iunlock(m)]: Defect

Ошибки типа Race Conditional представляют собой обращения к разделяемому объекту в параллельных блоках программы, если хотя бы одно из обращений является обращением на запись. Для обнаружения таких ошибок проверяются операции над разделяемыми объектами, выполняющиеся в параллельных блоках. Операции связанные с использованием (чтением значения) разделяемого объекта e в блоке Sij обозначим use(e) £ Sj Правила обнаружения ошибок типа Race Conditional выглядят следующим образом:

3S*,S£ :S£ \\ S£,useje)е 5*,def{e)e

RaceCondition 3S* ,S£:S£\ I S£,def{e)e S£,def{e)e S£ RaceCondition

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

последовательных программ на многопоточные программы. Данный подход обеспечивает получение полных результатов. В его основе алгоритм анализа потоков программы. Вычислительная сложность этого алгоритма зависит от количества конструкций синхронизации, в которых используется множество допустимых комбинаций. Сложность анализа одной такой конструкции оценивается как 0(пк • к2 • ^(к • п)), где к - число параллельно выполняющихся потоков; п - число блоков, параллельных блоку перед конструкцией синхронизации.

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

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

учитываются все взаимные влияния между алгоритмами анализа, что позволяет получать полные результаты;

обеспечивается совместное выполнение алгоритмов, что дает возможность получать более точные результаты по сравнению с итеративными подходами [12];

анализ состояния объектов на основе комбинаций позволяет точнее строить отношения параллельности и синхронизации по сравнению с классическими алгоритмами lockset-анализа;

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

СПИСОК ЛИТЕРАТУРЫ

1. Nielson, F. Principles of Program Analysis [Текст]/ F. Nielson, H.R. Nielson, C. Hankin. -Berlin, Springer, 2005. - 452 p.

2. Callahan, D. Analysis of Event Synchronization in Parallel Programming Tool [Текст]Ю. Callahan, K. Kennedy, J. Subhlok // Proc. of the 2 ACM SIGPLAN symp. on Principles & practice of parallel programming. - ACM NY, 1990.

3. Stoltz, E. Static single assignment for explicitly parallel programs: Theory and Practice [Текст]/Е. Stoltz, H. Shrinivasan, J. Hook [et al.]//Proc. of the 20th ACM SIGPLAN-SIGACT symp. On Principles of programming

languages. - ACM NY, 1994.

4. Engler, D. Effective, Static Detection of Race Conditions and Deadlocks [Текст]/0. Engler, K. Ashcraft, X. Racer//Proc. of the 19th ACM symp. on Operating systems principles. - ACM NY, 2003.

5. Bouajjani, A. A Generic Approach to the Static Analysis of Concurrent Programs with Procedures [TeKCT]/A. Bouajjani, J. Esparza, T. Touili//Proc. of the 30th ACM SIGPLAN-SIGACT symp. on Principles of programming languages. - ACM NY, 2003.

6. Pratikakis, P. LOCKSMITH: Context-Sensitive Correlation Analysis for Race Detection [Текст]/Р

Pratikakis, J. Foster, M. Hicks//Proc. of the 2006 ACM SIGPLAN conf. on Programming language design and implementation. - ACM NY, 2006.

7. Qadeer, S. KISS: Keep It Simple and Sequential [Текст]^. Qadeer, D.Wu//Proc. of the ACM SIGPLAN 2004 conf. on Programming language design and implementation. - ACM NY, 2004.

8. Chugh, R. Dataflow Analysis for Concurrent Programs using Datarace Detection [Текст]/Я. Chugh, J. Voung, R. Jhala [et al.]// Proc. of the 2008 ACM SIGPLAN conf. on Programming language design and implementation. - ACM NY, 2008.

9. Ицыксон, В.М. Исследование средств построения моделей исходного кода программ на языках C и C++ [Текст]/В.М. Ицыксон, М.И. Глухих, А.В. Зо-

зуля [и др.]//Научно-технические ведомости СПбГПУ - 2009. - № 1.

10. Cytron, R. Efficiently Computing Static Single Assignment Form and the Control Dependence Graph [Текст]/Я. Cytron [et al.]//ACM Transactions on Programming Languages and Systems. - ACM NY, 1991.-Vol. 13.-№ 4.

11. Ramanujam, J. Languages and Compilers for Parallel Computing. Analysis of Event Synchronization in Parallel Programs [Текст]Л. Ramanujam, A. Mathew. -Berlin, Springer, 1995.-P. 300-315.

12. Моисеев, М.Ю. Итеративный алгоритм статического анализа для обнаружения дефектов в исходном коде программ [Текст]/М.Ю. Моисеев // Информационные и управляющие системы.-2009.-№ 3.

УДК 004.021

А.А. Иванков, Д.С. Елисеев

ДИНАМИЧЕСКОЕ ОТСЛЕЖИВАНИЕ МОДУЛЕМ ИНФОРМАЦИОННО-ПОИСКОВОЙ СИСТЕМЫ ИЗМЕНЕНИЙ В СТРУКТУРЕ ИЛИ ТЕКСТЕ ИНТЕРНЕТ-РЕСУРСА

В данной статье предлагается решение задачи динамического отслеживания программными средствами информационно-поисковой системы (ИПС) изменений Интернет-ресурса на основе анализа изменений в его структуре или содержании. В качестве Интернет-ресурса (далее - документа) будем рассматривать только HTML-страницы. Опыт работы с собственной ИПС [1-3] позволяет утверждать, что подавляющее большинство веб-серверов по-прежнему предоставляют доступ к своим ресурсам в формате HTML-страниц. Мы не ставили перед собой задачу анализа документов в форматах XML, RDF и т. п. Они слишком редко встречаются в процессе обхода роботами нашей ИПС веб-серверов, изменения ресурсов которых представляют для нас интерес. Реализованные нами алгоритмы сравнительно просто расширить и на упомянутые выше форматы. Изменениями в структуре или содержании HTML-страницы будем оперировать как количественными характеристиками, задав соответствующие метрики.

Важность этой задачи вызвана тем, что БД ИПС должна, по возможности, содержать актуальную копию документа или отдельных его частей. В случае веб-сервера, который предоставляет доступ к данному документу и корректно обрабатывает запрос клиента «If-Modified-Since», такую задачу приходится решать всякий раз, когда изменяется значение атрибута «Last Modified» этого документа. Для документов, которые хранятся на веб-серверах, где администрирование организовано недостаточно профессионально, эту задачу решаем с определенной периодичностью. Когда атрибуты документа указывают, что последний претерпел какие-то изменения, естественным образом возникает еще одна задача - обнаружение, локализация этих изменений в структуре и содержании HTML-страницы. Следует подчеркнуть, что мы имеем в виду еще и алгоритмы для сбора данных, которые периодически обновляются и накапливаются на веб-серверах в течение достаточно длительного периода их существования. Примерами таких данных могут быть показатели