Справочник модулей анализа¶
Полная документация по модулям анализа кода в src/analysis/.
Содержание¶
- Обзор
- CFGAnalyzer
- Возможности
- Ключевые классы
- Справочник API
- Используемые таблицы базы данных
- FieldSensitiveTracer
- Возможности
- Ключевые классы
- Справочник API
- Категории чувствительных полей
- Используемые таблицы базы данных
- DataFlowTracer
- Методы интеграции
- ControlFlowAnalyzer (Проверка патчей)
- Возможности
- Интеграция с CFGAnalyzer
- Классификация критичности циклов
- Примеры использования
- Аудит безопасности (Сценарий 2)
- Анализ сложности (Сценарий 5/6)
- Проверка патчей (Сценарий 9)
- Справочник схемы базы данных
- Ключевые таблицы для анализа
- Типы рёбер для потока данных
- Устранение неполадок
- “Метод не найден”
- “Данные CFG не найдены”
- “Доступы к полям не найдены”
- Соображения по производительности
- См. также
Обзор¶
Модули анализа обеспечивают расширенные возможности статического анализа на основе CPG (графа свойств кода), хранящегося в DuckDB:
| Модуль | Назначение | Ключевые сценарии |
|---|---|---|
| CFGAnalyzer | Анализ графа потока управления, метрики сложности | 5, 6, 13 (рефакторинг, производительность) |
| FieldSensitiveTracer | Отслеживание загрязнения с учётом полей объектов | 2, 8, 14 (безопасность, соответствие требованиям, расследование инцидентов) |
| DataFlowTracer | Универсальный интерфейс для анализа потоков данных | 2, 14 (безопасность, реагирование на инциденты) |
| CallGraphAnalyzer | Обход графа вызовов | 1, 12 (ввод в систему, пересечение репозиториев) |
| ConcurrencyAnalyzer | Обнаружение шаблонов блокировок/mutex’ов | 16 (параллелизм) |
| CloneDetector | Обнаружение дублированного кода | 7, 13 (рефакторинг) |
CFGAnalyzer¶
Файл: src/analysis/cfg_analyzer.py
Анализ на основе графа потока управления (CFG) с использованием таблицы edges_cfg для точного анализа потока управления.
Возможности¶
- Цикломатическая сложность: Сложность Маккейба по формуле
M = E - N + 2 - Перечисление путей: Поиск путей выполнения на основе DFS с обнаружением циклов
- Анализ доминаторов: Построение деревьев доминаторов и пост-доминаторов
- Извлечение структуры CFG: Получение узлов, рёбер, точек входа и выхода
Основные классы¶
@dataclass
class CFGStructure:
"""Описывает структуру CFG метода"""
method_name: str
method_full_name: str
nodes: List[int]
edges: List[Tuple[int, int]] # пары (источник, назначение)
entry_nodes: List[int]
exit_nodes: List[int]
node_count: int
edge_count: int
@dataclass
class CFGPath:
"""Описывает путь выполнения в CFG"""
path_id: str
nodes: List[int]
length: int
has_loop: bool = False
Справочник API¶
CFGAnalyzer(cpg_service)¶
Инициализация с экземпляром CPGQueryService или подключением DuckDB.
get_method_cfg(method_name: str) -> Optional[CFGStructure]¶
Получить структуру CFG для метода.
from src.analysis.cfg_analyzer import CFGAnalyzer
analyzer = CFGAnalyzer(cpg_service)
cfg = analyzer.get_method_cfg("heap_insert")
print(f"Узлы: {cfg.node_count}, Рёбра: {cfg.edge_count}")
compute_cyclomatic_complexity(method_name: str) -> int¶
Вычислить цикломатическую сложность Маккейба: M = E - N + 2
complexity = analyzer.compute_cyclomatic_complexity("heap_insert")
print(f"Сложность: {complexity}") # например, 15
enumerate_paths(method_name: str, max_paths: int = 100) -> List[CFGPath]¶
Найти пути выполнения в CFG с обнаружением циклов.
paths = analyzer.enumerate_paths("process_query", max_paths=50)
for path in paths:
print(f"Путь {path.path_id}: {path.length} узлов, цикл={path.has_loop}")
find_dominators(method_name: str) -> Dict[int, Set[int]]¶
Построить дерево доминаторов с использованием таблицы edges_dominate.
find_post_dominators(method_name: str) -> Dict[int, Set[int]]¶
Построить дерево пост-доминаторов с использованием таблицы edges_post_dominate.
analyze_complexity_distribution() -> Dict[str, Any]¶
Проанализировать распределение сложности по всем методам в кодовой базе.
dist = analyzer.analyze_complexity_distribution()
print(f"Средняя сложность: {dist['average']}")
print(f"Методы с высокой сложностью: {dist['high_complexity_methods']}")
Используемые таблицы базы данных¶
nodes_method— Метаданные методовedges_contains— Связи методов с узламиedges_cfg— Рёбра графа потока управления (CFG) между узламиedges_dominate— Отношения доминированияedges_post_dominate— Отношения пост-доминирования
FieldSensitiveTracer¶
Файл: src/analysis/field_sensitive_tracer.py
Отслеживание путей полей для точного анализа заражения (taint analysis), с различением различных полей одного и того же объекта.
Возможности¶
- Разбор путей к полям: Обработка цепочек вида
obj.field1.field2иobj->field->data - Отслеживание доступа к полям: Поиск всех чтений/записей в конкретные поля
- Распространение заражения: Отслеживание заражённых данных через доступ к полям
- Обнаружение чувствительных полей: Выявление потоков данных из чувствительных полей (пароль, токен и т.д.)
Основные классы¶
@dataclass
class FieldPath:
"""Представляет путь доступа к полю, например obj.field1.field2"""
base_variable: str
field_chain: List[str]
full_path: str
node_ids: List[int]
type_full_name: Optional[str]
@dataclass
class FieldAccess:
"""Представляет один доступ к полю в коде"""
node_id: int
base_variable: str
field_name: str
access_code: str
line_number: int
filename: str
access_type: str # 'read', 'write', 'call'
containing_method: Optional[str]
@dataclass
class FieldSensitiveFlow:
"""Путь передачи данных с учётом полей"""
source_path: FieldPath
sink_path: FieldPath
intermediate_fields: List[FieldPath]
is_tainted: bool
relationship: str # 'exact', 'prefix', 'suffix', 'propagated'
confidence: float
Справочник API¶
FieldSensitiveTracer(cpg_service)¶
Инициализация с CPGQueryService или подключением DuckDB.
parse_field_path(code: str) -> FieldPath¶
Разбирает строку доступа к полю в структурированный объект FieldPath.
from src.analysis.field_sensitive_tracer import FieldSensitiveTracer
tracer = FieldSensitiveTracer(cpg_service)
# Разбор нотации указателей {#parse-pointer-notation}
path = tracer.parse_field_path("user->password")
print(path.base_variable) # "user"
print(path.field_chain) # ["password"]
# Разбор нотации через точку {#parse-dot-notation}
path = tracer.parse_field_path("request.data.buffer")
print(path.full_path) # "request.data.buffer"
get_struct_fields(struct_name: str) -> List[Dict]¶
Получает поля, определённые в структуре, с информацией о типах.
fields = tracer.get_struct_fields("UserData")
for field in fields:
print(f"{field['name']}: {field['type']}")
find_field_accesses(base_var: str, field_name: str) -> List[FieldAccess]¶
Находит все обращения к конкретному полю.
accesses = tracer.find_field_accesses("user", "password")
for access in accesses:
print(f"{access.filename}:{access.line_number} - {access.access_type}")
trace_field_taint(source_field: str, sink_functions: List[str]) -> List[FieldSensitiveFlow]¶
Отслеживает заражение от исходного поля до функций-приёмников (sinks).
flows = tracer.trace_field_taint(
source_field="credentials->password",
sink_functions=["printf", "log", "send"]
)
for flow in flows:
print(f"Заражённый поток: {flow.source_path} -> {flow.sink_path}")
find_sensitive_field_flows(sensitive_fields: List[str] = None, sink_functions: List[str] = None) -> List[FieldSensitiveFlow]¶
Находит потоки данных из чувствительных полей в опасные приёмники.
# Чувствительные поля по умолчанию: password, token, secret, private_key, credential, auth {#default-sensitive-fields-password-token-secret-private-key-credential-auth}
flows = tracer.find_sensitive_field_flows()
print(f"Найдено {len(flows)} потенциальных утечек чувствительных данных")
Категории чувствительных полей¶
Чувствительные поля, отслеживаемые по умолчанию:
- password, passwd, pwd
- token, auth_token, access_token
- secret, api_secret, client_secret
- private_key, secret_key
- credential, credentials
- auth, authorization
Используемые таблицы базы данных¶
nodes_field_identifier— узлы доступа к полямnodes_identifier— идентификаторы переменныхnodes_member— определения полей структурedges_reaching_def— рёбра достижимых определенийedges_argument— рёбра аргументов функций
DataFlowTracer¶
Файл: src/analysis/dataflow_tracer.py
Фасадный модуль, предоставляющий единый интерфейс к возможностям анализа потоков данных.
Методы интеграции¶
DataFlowTracer обеспечивает интеграцию базового анализа потоков данных и анализа с учётом полей:
find_taint_paths_field_sensitive(source_functions, sink_functions, track_fields=True, max_depth=10) -> List[DataFlowPath]¶
Расширенный анализ заражения (taint analysis) с опциональным отслеживанием полей.
from src.analysis.dataflow_tracer import DataFlowTracer
tracer = DataFlowTracer(cpg_service)
# Поиск путей заражения с учётом полей {#find-taint-paths-with-field-sensitivity}
paths = tracer.find_taint_paths_field_sensitive(
source_functions=["getenv", "fgets", "read"],
sink_functions=["system", "exec", "popen"],
track_fields=True,
max_depth=10
)
for path in paths:
print(f"Источник: {path.source} -> Приёмник: {path.sink}")
print(f"Обращения к полям: {path.field_accesses}")
find_sensitive_data_flows(sensitive_fields=None, sink_functions=None) -> List[Dict]¶
Обёртка вокруг FieldSensitiveTracer для типовых задач анализа безопасности.
# Использование значений по умолчанию для распространённых шаблонов {#use-defaults-for-common-patterns}
flows = tracer.find_sensitive_data_flows()
# Или с настройкой под задачу {#or-customize}
flows = tracer.find_sensitive_data_flows(
sensitive_fields=["api_key", "bearer_token"],
sink_functions=["http_request", "socket_send"]
)
ControlFlowAnalyzer (Просмотр изменений)¶
Файл: src/patch_review/analyzers/control_flow_analyzer.py
Анализирует влияние изменений на поток управления, теперь с использованием CFGAnalyzer для точного расчёта метрик.
Возможности¶
- Расчёт дельты сложности (до/после внесения изменений)
- Обнаружение новых циклов с классификацией рисков
- Отслеживание изменений в обработке ошибок
- Оценка влияния на покрытие ветвлений
Интеграция с CFGAnalyzer¶
from src.patch_review.analyzers.control_flow_analyzer import PatchControlFlowAnalyzer
analyzer = PatchControlFlowAnalyzer(cpg_service)
# Анализ влияния изменений {#analyze-patch-impact}
result = analyzer.analyze_control_flow_changes(patch_data)
print(f"Дельта сложности: {result.complexity_delta}")
print(f"Новые циклы: {len(result.new_loops)}")
print(f"Изменения в обработке ошибок: {len(result.error_handling_changes)}")
Классификация серьёзности циклов¶
Новые циклы классифицируются по уровню риска: - HIGH (Высокий): Вложенные циклы, циклы с операциями ввода-вывода, неограниченные циклы - MEDIUM (Средний): Циклы с внешними вызовами - LOW (Низкий): Простые ограниченные циклы
Примеры использования¶
Аудит безопасности (Сценарий 2)¶
from src.analysis.field_sensitive_tracer import FieldSensitiveTracer
tracer = FieldSensitiveTracer(cpg_service)
# Поиск утечек паролей {#find-password-leaks}
flows = tracer.find_sensitive_field_flows(
sensitive_fields=["password", "credentials"],
sink_functions=["printf", "fprintf", "syslog", "elog"]
)
for flow in flows:
print(f"ОПАСНО: {flow.source_path} попадает в {flow.sink_path}")
Анализ сложности (Сценарий 5/6)¶
from src.analysis.cfg_analyzer import CFGAnalyzer
analyzer = CFGAnalyzer(cpg_service)
# Анализ всех методов {#analyze-all-methods}
dist = analyzer.analyze_complexity_distribution()
# Поиск кандидатов на рефакторинг {#find-refactoring-candidates}
for method in dist['high_complexity_methods']:
print(f"Кандидат на рефакторинг: {method['name']} (сложность={method['complexity']})")
Проверка патча (Сценарий 9)¶
from src.patch_review.analyzers.control_flow_analyzer import PatchControlFlowAnalyzer
analyzer = PatchControlFlowAnalyzer(cpg_service)
result = analyzer.analyze_control_flow_changes(patch)
if result.complexity_delta > 10:
print("ВНИМАНИЕ: Значительное увеличение сложности")
for loop in result.new_loops:
if loop.severity == 'HIGH':
print(f"ОПАСНО: Цикл высокого риска в методе {loop.method_name}")
Справочник по схеме базы данных¶
Основные таблицы для анализа¶
| Таблица | Назначение |
|---|---|
| nodes_method | Определения методов |
| nodes_control_structure | Структуры управления потоком выполнения (if, for, while) |
| nodes_field_identifier | Выражения доступа к полям |
| nodes_identifier | Ссылки на переменные |
| edges_cfg | Рёбра графа потока управления |
| edges_contains | Отношения вложенности (содержимое) |
| edges_dominate | Отношения доминирования |
| edges_reaching_def | Рёбра достижимых определений |
| edges_argument | Рёбра аргументов функций |
Типы рёбер для анализа потока данных¶
| Тип ребра | Таблица | Назначение |
|---|---|---|
| CFG | edges_cfg | Поток управления между операторами |
| REACHING_DEF | edges_reaching_def | Цепочки «определение — использование» |
| ARGUMENT | edges_argument | Аргументы вызова функций |
| CONTAINS | edges_contains | Вложенность областей видимости |
Устранение неполадок¶
“Метод не найден”¶
Имя метода должно совпадать точно (с учетом регистра). Используйте простое имя, а не полное квалифицированное.
# Правильно {#correct}
cfg = analyzer.get_method_cfg("heap_insert")
# Неправильно {#incorrect}
cfg = analyzer.get_method_cfg("heap_insert(Relation, HeapTuple)")
“Данные CFG не найдены”¶
Убедитесь, что экспорт CPG включал ребра CFG. Проверьте, есть ли данные в таблице edges_cfg:
SELECT COUNT(*) FROM edges_cfg;
“Обращения к полям не найдены”¶
Для отслеживания обращений к полям необходимы данные nodes_field_identifier:
SELECT COUNT(*) FROM nodes_field_identifier;
Рекомендации по производительности¶
- Перечисление путей ограничено параметром
max_paths, чтобы предотвратить экспоненциальный рост - Используйте
max_depthдля ограничения глубины отслеживания передачи зараженных данных (taint) - В больших методах может быть очень много путей; рассмотрите возможность выборки
Смотрите также¶
- Справочник по схеме — Полная схема базы данных
- Кулинарная книга SQL-запросов — Примеры запросов
- Справочник по агентам — Конвейер агентов
- Руководство по сценариям — Сценарии использования