Привет, Хабр!

На связи Федорова Валерия, участница профессионального сообщества NTA.

Каждый разработчик был, или может оказаться, в ситуации, когда не понимаешь, как работает код, который был написан пару дней (недель, месяцев, лет — нужное подчеркнуть) назад. Или в еще более сложной ситуации — нужно «отдебажить» чужой код, без возможности привлечь автора. Здесь может пригодиться один из инструментов статистического анализа кода — 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 

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

Запускаю и тестирую Staticfg

Начну с установка библиотеки 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')

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

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

CFG тестовой программы
CFG тестовой программы

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

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

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

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

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

Вместо заключения

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

Комментарии (10)


  1. phaggi
    22.06.2023 05:31
    +1

    Любопытно, поймет ли эта программа, к примеру, вот этот почти классический уже код из тьюториала по тестированию на Selenium. И поймем ли мы то, что она отобразит.


  1. DvoiNic
    22.06.2023 05:31
    +1

    "Control Flow Graph" — это точно "Граф управления потоком"?
    что-то после таких статей закрадываются сомнения в профессиональности "профессионального сообщества"


    1. NewTechAudit Автор
      22.06.2023 05:31

      Добрый день!

      Спасибо большое за замечание. Конечно же "граф потока управления", внесли исправления в пост.


      1. DvoiNic
        22.06.2023 05:31

        во-первых, не везде внесли. а во-вторых, автор представлял, о чем пишет, когда писал? ну ведь реально глаз режет.


        1. NewTechAudit Автор
          22.06.2023 05:31

          Спасибо большое! С автора возьмем объяснение.


          1. Orbit67
            22.06.2023 05:31

            И расписку с него возьмите, что больше так не будет.


  1. anonymous
    22.06.2023 05:31

    НЛО прилетело и опубликовало эту надпись здесь


    1. NewTechAudit Автор
      22.06.2023 05:31

      Спасибо за интерес к посту!


  1. forthuse
    22.06.2023 05:31

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

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


    1. DvoiNic
      22.06.2023 05:31

      тем не менее, польза вполне может быть. Я давненько, лет 8 назад, игрался с отображением кода в граф (тоже, кстати, graphviz'ом отображал). Не сказал бы, что уж очень полезно, но интересно. Для практической пользы надо drill-down было доделать… Но тут классическая дилемма — в мелком проекте графика не нужна, а в крупном графика только "нагрузит"