Время прочтения: 4 мин.

Каждый разработчик был в такой ситуации, когда не понимаешь, как работает код, который был написан пару дней назад. Или в еще более сложной ситуации – нужно было «отдебажить» чужой код, без возможности привлечь автора. Здесь может пригодиться один из инструментов статистического анализа кода – Control Flow Graph или CFG.

В этой публикации рассмотрю понятие CFG, а также python библиотеку Staticfg, обеспечивающую простой интерфейс для создания CFG программ на языке Python.

Граф управления потоком (Control Flow Graph, CFG) – это граф, где узлы представляют базовые блоки кода, а ребра представляют переходы между ними. В статическом анализе кода, CFG может быть использован для обнаружения потенциальных проблем в коде. Например, CFG может помочь выявить «мертвый» код (код, который может быть исполнен, но результаты его вычислений не влияют на дальнейшую программу) или недостижимые части программы. CFG также может быть использован для оптимизации кода. Например, CFG может помочь выявить повторяющиеся участки кода, которые могут быть заменены на вызов функции. CFG используется во многих языках программирования, в том числе в C, C++, Java, Python и других. Они могут быть созданы вручную или автоматически с помощью инструментов, таких как библиотека Staticfg на языке Python.

Staticfg — это Python библиотека, которая позволяет создавать графы управления потоком, или простыми словами, схемы взаимодействия блоков кода. Использование staticfg может быть полезно для: исследования кода, разработки инструментов для статического анализа кода, анализа производительности кода, анализа безопасности кода. Она поддерживает большинство основных конструкций языка, таких как условные операторы, циклы и вызовы функций.

Установка библиотеки производится командой:

pip install staticfg

Staticfg визуализирует граф с помощью Graphviz. Поэтому не забудьте его установить, и путь до него добавить в переменную среды. Это можно сделать следующим кодом:

import os
os.environ["PATH"] += os.pathsep + r'C:\Program Files (x86)\Graphviz2.38\bin'

Одним из примеров использования Staticfg может быть следующий код:

#импортируем нужный модуль
from staticfg import CFGBuilder
#создаем объект класса CFGBuilder
cfg = CFGBuilder().build_from_file('example','example.py')
#сохраняем визуализацию
cfg.build_visual('example','png')

Этот код создаст граф потока управления для файла example.py и сохранит его в формате png с названием example.

Для примера я написала простой код, который выводит числа от 1 до 10 и их факториалы. Получился такой граф:

Рис.1 CFG тестовой программы

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

Граф программы демонстрирует, что сначала объявляется функция factorial, затем в цикле по i от 0 до 9 вызывается стандартная функция print, которая выводит пары: число i+1 и результат работы функции factorial, которой подается на вход число i+1.

Граф функции факториал показывает, что сначала переменной result присваивается значение 1, затем запускается цикл, который вычисляет факториал числа n (поданного на вход функции) и присваивает его переменной result, значение которой возвращается далее после цикла.

Подобные графы помогают понять логику работы программы, наглядно иллюстрируя ее алгоритм.

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

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