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

от автора

0940_AkkaNET_Error_ru/image1.png

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

Ошибка

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

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;   }   .... }

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

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

HashSet<T>.Add:

_shards.Add(shardId);

HashSet<T>.UnionWith:

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

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

_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

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

_shards.UnionWith(state.Shards);

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

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

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

Подробнее про систему писали здесь.

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

20.04.2022:

  • в dev-ветку проекта Akka.NET попадает код с ошибкой (ссылка на конкретную строку);

21.04.2022:

  • код анализируется у нас на сервере, и мне приходит письмо с информацией о предупреждениях;
  • я изучаю проблему и открываю issue на GitHub;
  • разработчики исправляют ошибку. Ссылка на коммит.

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

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

Что делать?

  • Использовать статический анализатор. Загрузить можно здесь. Если применить промокод pvs_akka, триал будет работать 30 дней, а не 7.
  • Подписаться на меня в Twitter, если интересует подобный контент.

P.S. Если хотите поделиться статьёй с англоязычной аудиторией, вот ссылка на англ. версию.


ссылка на оригинал статьи https://habr.com/ru/company/pvs-studio/blog/662832/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *