Попова В.А. Применение методики статического анализа для выявления ошибок в программах на динамических языках программирования. Современные среды разработки содержат инструменты, которые позволяют без запуска программ выявлять ошибки и недостатки в исходных текстах на языках программирования, а также выполнять рефакторинг программного кода различной степени сложности. Одной из важных проблем, которая существенно влияет на качество разрабатывающихся программных систем, является возникновение ошибок несоответствия типов. Для языков программирования с динамической типизацией ошибки такого рода могут быть выявлены только во время выполнения программного кода. В данной работе описываются полученные результаты применения статического анализа к языку программирования с динамической типизацией «1С: Предприятие».
Ключевые слова: качество программных систем, статический анализ кода, динамическая типизация, система типов, абстрактное синтаксическое дерево
Для всех языков программирования существуют правила [1], которые требуется соблюдать при написании программного кода, чтобы разрабатывающаяся система была работоспособной, обладала необходимой функциональностью и соответствовала стандартам качества. Так, правила, ставящие в соответствие конструкциям программы типы данных, образуют логическую систему, которая называется системой типов [2].
Языки программирования по характеристике типизации делятся на типизированные и бестиповые (нетипизированные). Нетипизированными называются языки программирования, в которых доступно производить любые операции над данными, которые рассматриваются только в качестве последовательности бит различной длины [3]. К группе нетипизированных языков относятся как низкоуровневый язык ассемблер, так и высокоуровневые, например, BCPL, Forth.
В типизированных языках программирования для каждой операции определяется набор типов, к которому она может быть применима. Типизированные языки программирования по характеристике проверки соответствия типов конструкциям подразделяются на статические и динамические.
В программах, написанных на языках со статической типизацией, для устранения ошибок несоответствия типов требуется меньше затрат, поскольку ошибки выявляются в процессе разработки или тестирования, а не при использовании программы пользователями. В динамически типизированных языках программирования типы конструкций не вычисляются при компиляции, поскольку могут быть определены только в процессе выполнения программного кода.
В программах, написанных на языках программирования с динамической типизацией, существует риск выполнить недопустимое преобразование типов, из-за чего программа может аварийно завершать свою работу или не выполнять до конца ту или иную операцию, если разработчиком не была предусмотрена обработка критической ситуации. Ввиду подобных проблем пользователям становится труднее использовать программное обеспечение и требуется ожидать исправления ошибок разработчиками, на что может потребоваться достаточно большое количество времени.
Для отслеживания ошибок, возникающих в результате динамической проверки типов, следует использовать механизмы, которые позволяют анализировать код программы без её запуска. На сегодняшний день для подобных задач используется методика статического анализа программного кода.
Для некоторых языков программирования с динамической типизацией существуют механизмы, которые позволяют выполнять статический анализ по исходному коду программ. Например, разработан алгоритм Хиндли-Милнера [4], который позволяет провести преобразования на уровне синтаксиса для автоматического определения типов выражений, использующихся в программе. На системе типов Хиндли-Милнера основаны такие языки, как Standard ML, OCaml, Haskell.
Для языка программирования JavaScript компанией Google был создан механизм статической проверки типов на языке программирования Java в рамках проекта Closure Compiler.
Также существует набор технологий компилятора LLVM (Low Level Virtual Machine), которые позволяют проверять соответствия типов в поддерживаемых проектом LLVM языках программирования как со статической типизацией (C, C++), так и с динамической (Julia, PHP, Python и т.д.).
Существующие статические анализаторы программного кода осуществляют проверку корректности использования конструкций языка, исследуя абстрактное синтаксическое дерево, а также определяют вызовы методов, чтобы смоделировать поведение объектов в определённой точке выполнения программного кода [5].
Абстрактное синтаксическое дерево (Abstract Syntax Tree – AST) – это представление программного кода, которое отражает связи между элементами выражений [6]. В AST вершинами являются операторы выражений, а листьями – аргументы (операнды).
Для того чтобы построить AST, необходимо выполнить лексический и синтаксический анализ программы [7]. Целью лексического анализа является выявление в программном коде лексем, к которым относятся ключевые слова, знаки операций, некоторые фиксированные значения (литералы) и т.д. После определения лексем выполняется синтаксический анализ, суть которого заключается в сопоставлении лексем в соответствие грамматике, определённой для использующегося языка программирования. На основании результатов синтаксического анализа можно выполнить построение AST.
К настоящему моменту для встроенного языка программирования в платформу «1С: Предприятие» не существует механизмов статического анализа, позволяющих выявлять ошибки несоответствия типов, которые могут возникать в разрабатывающихся конфигурациях. В связи с этим возникла идея создания механизма статической проверки типов для программ, разработанных на платформе «1С: Предприятие».
Помимо применения правил вычисления типов по исходному тексту программы, при разработке механизма статической проверки необходимо использовать информацию о типах языка, встроенного в платформу «1С: Предприятие». Результаты работы по анализу системы типов и процессу извлечения информации о типах конфигураций «1С: Предприятия» описаны в [8] и [9] соответственно.
В рамках работы по разработке механизма статического анализа был создан формат для описания объектов конфигурации и типов платформы «1С: Предприятие». Такой формат был назван «Дерево типов конфигурации» (ДТК). Название обусловлено тем, что каждый объект конфигурации наследует функциональность одного или нескольких типов, определённых в платформе «1С: Предприятие».
Файл формата ДТК состоит из:
- типов платформы («ветки дерева») – служат основанием для объектов конфигурации;
- объектов конфигурации («листья дерева») – наследуют функциональность типов платформы.
Для того чтобы разработать средство статической проверки типов, требовалось получить представление программного кода конфигурации в формате AST, а уже далее выполнять анализ соответствия типов конструкциям языка, применяя информацию из документа формата ДТК.
Программный комплекс, который применяет методы статического анализа типов к свойствам языка программирования «1С: Предприятие», разрабатывается на языке программирования C++. К настоящему моменту реализовано следующее:
- выполнение лексического и синтаксического анализа программного кода конфигураций «1С: Предприятия»;
- преобразование структуры методов в представление AST;
- выполнение процедуры статического анализа с применением информации о типах из документа формата ДТК.
Процесс статической проверки типов начинается из точек входа, которыми являются методы, определяющие такие события приложения, как, например, ПриНачалеРаботыСистемы() и ПриЗавершенииРаботыСистемы().
В процессе тестирования программного комплекса были выявлены следующие ошибки:
- некорректной передачи параметров в метод;
- обращения к отсутствующему свойству объекта;
- попытке выполнить перебор, предполагая, что переменная имеет тип коллекции значений.
Например, если в метод платформы СтрЭаменить(...), который содержит 3 параметра типа Строка, передать параметры другого типа, то будет сформировано сообщение об ошибке с указанием, какие параметры передаются некорректно. Информация об ошибках несоответствия типов записывается в файл. Для каждой ошибки указывается, в каком модуле и в какой строке она находится.
Затем осуществлялась доработка формата ДТК для того, чтобы при выполнении статического анализа также иметь возможность анализировать не только методы, но и события, которые инициируются пользователем при взаимодействии с формами, располагающимися в пользовательском интерфейсе. Таким образом, из документации требовалось извлечь данные о событиях пользовательского интерфейса и, соответственно, дополнить файл формата ДТК.
Извлечённая информация о событиях позволила определить новые точки входа в программу: если ранее такими точками были события приложения, то теперь являются и реализованные события для элементов и команд, которые расположены в пользовательских формах. Это обусловлено тем, что выполнение программного кода осуществляется не только при запуске режима «1С: Предприятия». Некоторые фрагменты кода выполняются при работе пользователя с элементами и командами в случае, если для них переопределена функциональность событий встроенного языка.
На текущий момент ведётся работа над поиском ошибок в использовании элементов пользовательского интерфейса. Например, элементы могут быть вложены в группы, свойства которых можно настраивать в программном коде.
В результате работы был усовершенствован на основании предыдущих наработок авторов механизм статического анализа для поиска ошибок несоответствия типов в программах, написанных на языке программирования «1С: Предприятие».
Разработанный программный комплекс может стать полезным инструментом в процессе создания конфигураций на платформе «1С: Предприятие», поскольку его функциональность позволяет находить значительное количество ошибок в программах ещё на этапе разработки.