﻿# Зачем нужен статический анализ? Разбираем на примере ошибки из Akka\.NET

"Статический анализ нужно использовать регулярно, а не только перед релизами\.\.\. Чем раньше найдена ошибка, тем дешевле её исправление\.\.\." – вы уже слышали это 100 раз\. Сегодня ещё раз ответим на вопрос "зачем?"\. Поможет нам ошибка из проекта Akka\.NET\. 

![0940_AkkaNET_Error_ru/image1.png](https://import.viva64.com/docx/blog/0940_AkkaNET_Error_ru/image1.png)

**Ошибка**

Начнём с задания\. Нужно найти дефект в этом фрагменте кода:

```cpp
protected override bool ReceiveRecover(object message)
{
  switch (message)
  {
    case ShardId shardId:
      _shards.Add(shardId);
      return true;
    case SnapshotOffer offer when (offer.Snapshot is 
                                   ShardCoordinator.CoordinatorState state):
      _shards.UnionWith(state.Shards.Keys.Union(state.UnallocatedShards));
      return true;
    case SnapshotOffer offer when (offer.Snapshot is State state):
      _shards.Union(state.Shards);
      _writtenMarker = state.WrittenMigrationMarker;
      return true;
    case RecoveryCompleted _:
      Log.Debug("Recovery complete. Current shards [{0}]. Written Marker {1}", 
                string.Join(", ", _shards), 
                _writtenMarker);

      if (!_writtenMarker)
      {
        Persist(MigrationMarker.Instance, _ =>
        {
          Log.Debug("Written migration marker");
          _writtenMarker = true;
        });
      }
      return true;
    case MigrationMarker _:
      _writtenMarker = true;
      return true;
  }
  ....
}
```

Разберём, в чём тут дело\.

Тип переменной _\_shards_ – _HashSet<ShardId\>_\. В приведённом выше коде вызываются несколько методов, которые изменяют состояние этого множества\.

_HashSet<T\>\.Add_:

```cpp
_shards.Add(shardId);
```

_HashSet<T\>\.UnionWith_: 

```cpp
_shards.UnionWith(state.Shards.Keys.Union(state.UnallocatedShards));
```

Однако один из вызовов – неправильный: 

```cpp
_shards.Union(state.Shards);
```

Он не меняет состояние объекта _\_shards_\. _Enumerable\.Union_ – метод\-расширения из LINQ, который возвращает изменённую коллекцию, а не меняет исходную\. Значит, результат вызова метода должен быть или куда\-то сохранён, или как\-то использован\. Этого в коде тоже нет\.

Анализатор PVS\-Studio выдал такое предупреждение: _V3010 The return value of function 'Union' is required to be utilized\. Akka\.Cluster\.Sharding EventSourcedRememberEntitiesCoordinatorStore\.cs 123_

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

```cpp
_shards.UnionWith(state.Shards);
```

**Как мы нашли ошибку или в 101\-ый раз о пользе статического анализа** 

У нас на сервере каждую ночь запускается анализ нескольких Open Source проектов\. В их числе – Akka\.NET\. Это помогает:

* дополнительно тестировать анализатор;
* рассказывать о пользе стат\. анализа в подобных заметках\.

Подробнее про систему писали [здесь](https://pvs-studio.ru/ru/blog/posts/cpp/0799/)\.

А теперь немного хронологии появления и исправления проблемы\.

_20\.04\.2022:_

* в dev\-ветку проекта Akka\.NET [попадает](https://github.com/akkadotnet/akka.net/commit/2cbdbcbd07ac65596a8a38eb30e54ba22041d1b1) код с ошибкой \([ссылка](https://github.com/akkadotnet/akka.net/blob/8e7f02149451856c9160f9cd28d687ff8a166a11/src/contrib/cluster/Akka.Cluster.Sharding/Internal/EventSourcedRememberEntitiesCoordinatorStore.cs#L123) на конкретную строку\);

_21\.04\.2022:_

* код анализируется у нас на сервере, и мне приходит письмо с информацией о предупреждениях;
* я изучаю проблему и открываю [issue](https://github.com/akkadotnet/akka.net/issues/5862) на GitHub;
* разработчики исправляют ошибку\. [Ссылка](https://github.com/akkadotnet/akka.net/pull/5863/commits/263a459e11e4d1a273819b728f0dcc5cb7320934) на коммит\.

Считаю, что отработали слаженно и оперативно\. Разработчикам уважение за быстрый фикс\.

Как долго эта ошибка существовала бы в коде, если бы события развивались иначе? Оставляю возможность пофантазировать самим\.

**Что делать?**

* Использовать статический анализатор\. Загрузить можно [здесь](https://pvs-studio.ru/ru/pvs-studio/try-free/?promo=pvs_akka)\. Если применить промокод _pvs\_akka_, триал будет работать 30 дней, а не 7\.
* [Подписаться](https://twitter.com/_SergVasiliev_) на меня в Twitter, если интересует подобный контент\.