﻿# Межпроцедурный контекстно\-чувствительный анализ

Статические анализаторы кода могут учитывать данные, которые передаются между процедурами/функциями, чтобы выявить больше ошибок и [потенциальных уязвимостей](https://pvs-studio.ru/ru/blog/terms/6441/)\. Это важно при выявлении таких ошибок, как утечки памяти, разыменование нулевых указателей, выход за границы массивов и т\.д\. Это связано с тем, что создание некого ресурса, его использование и освобождение часто разнесены по разным функциях\.

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

Поясним это на примере реальной ошибки, [найденной](https://pvs-studio.ru/ru/blog/posts/csharp/0966/) с помощью анализатора PVS\-Studio в коде проекта AvalonStudio \(C\#\)\.

Рассмотрим в начале функцию _IsBuiltInType_\. Обратите внимание, что если её входной аргумент _cursor_ окажется нулевой ссылкой, то функция вернёт значение _false_\.

```cpp
private static bool IsBuiltInType(ClangType cursor)
{
  var result = false;
  if (cursor != null && ....)
  {
    return true;
  }
  return result;
}
```

Теперь рассмотрим другой фрагмент кода, где вызывается рассмотренная функция:

```cpp
private static StyledText InfoTextFromCursor(ClangCursor cursor)
{
  ....
  if (cursor.ResultType != null)
  {
    result.Append(cursor.ResultType.Spelling + " ",
                  IsBuiltInType(cursor.ResultType) ? theme.Keyword 
                                                   : theme.Type);
  }
  else if (cursor.CursorType != null)
  {
    switch (kind)
    {
      ....
    }
    result.Append(cursor.CursorType.Spelling + " ",
                  IsBuiltInType(cursor.ResultType) ? theme.Keyword
                                                   : theme.Type);
  }
  ....
}
```

Если _cursor\.ResultType \!\= null_, то выполняется тело первого оператора _if_\. Соответственно, если управление будет предано внутрь тела второго оператора _if_, то точно известно, что ссылка _cursor\.ResultType_ является нулевой\.

Изучим место вызова рассмотренной ранее функции _IsBuiltInType_:

```cpp
result.Append(cursor.CursorType.Spelling + " ",
              IsBuiltInType(cursor.ResultType) ? theme.Keyword
                                               : theme.Type);
```

Анализатор знает, что _cursor\.ResultType_ — нулевая ссылка\. Из этого он делает вывод, что при таком входном аргументе **функция всегда возвращает _false_**\.

Это и есть межпроцедурный контекстно\-чувствительный анализ\.

Если условие тернарного оператора всегда ложно, то это подозрительно, о чём анализатор и сообщает, выдавая предупреждение:

[V3022](https://pvs-studio.ru/ru/docs/warnings/v3022/) Expression 'IsBuiltInType\(cursor\.ResultType\)' is always false\.

Действительно, если присмотреться к коду, то можно заметить опечатку\. В теле второго оператора _if_ при вызове функции _IsBuiltInType_ в качестве фактического аргумента следует передать переменную _cursor\.CursorType_\.

Исправленный вариант кода:

```cpp
private static StyledText InfoTextFromCursor(ClangCursor cursor)
{
  ....
  if (cursor.ResultType != null)
  {
    result.Append(cursor.ResultType.Spelling + " ",
                  IsBuiltInType(cursor.ResultType) ? theme.Keyword 
                                                   : theme.Type);
  }
  else if (cursor.CursorType != null)
  {
    switch (kind)
    {
      ....
    }
    result.Append(cursor.CursorType.Spelling + " ",
                  IsBuiltInType(cursor.CursorType) ? theme.Keyword
                                                   : theme.Type);
  }
  ....
}
```

<details>
   <summary>Определение межпроцедурного контекстно\\\-чувствительного анализа по ГОСТ Р 71207\\\-2024\\\.</summary>

[ГОСТ Р 71207\-2024](https://pvs-studio.ru/ru/pvs-studio/gost-71207/) — Статический анализ программного обеспечения\. В разделе терминов дано следующее определение межпроцедурного контекстно\-чувствительного анализа:

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

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


</details>
Ситуация усложняется, если требуется анализировать взаимодействие функций, находящихся в различных единицах трансляции/программных модулях\. В этом случае говорят, что выполняется межмодульный анализ\.

**Дополнительные ссылки**

1. [Статический анализ кода](https://pvs-studio.ru/ru/blog/terms/0046/)\.
1. Андрей Карпов\. [Как работает статический анализ](https://pvs-studio.ru/ru/blog/posts/1048/)?
1. Андрей Карпов\. [Что нельзя найти с помощью статического анализа](https://pvs-studio.ru/ru/blog/posts/1037/)\.