Для получения триального ключа
заполните форму ниже
Team License (базовая версия)
Enterprise License (расширенная версия)
* Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности

Запросите информацию о ценах
Новая лицензия
Продление лицензии
--Выберите валюту--
USD
EUR
RUB
* Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности

Бесплатная лицензия PVS-Studio для специалистов Microsoft MVP
* Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности

Для получения лицензии для вашего открытого
проекта заполните, пожалуйста, эту форму
* Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности

Мне интересно попробовать плагин на:
* Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности

Ваше сообщение отправлено.

Мы ответим вам на


Если вы так и не получили ответ, пожалуйста, проверьте папку
Spam/Junk и нажмите на письме кнопку "Не спам".
Так Вы не пропустите ответы от нашей команды.

>
>
>
Интересная ошибка в Entity Framework

Интересная ошибка в Entity Framework

23 Мар 2017

В последнее время в качестве хобби и заодно с целью популяризации нашего статического анализатора PVS-Studio мы выполняем проверки open-source проектов и по возможности выпускаем патчи с исправлениями. Сегодня я хотел бы поговорить об одной интересной ошибке, которую я нашёл в проекте Entity Framework.

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

А теперь ближе к делу. Анализатор выдал 2 предупреждения на одной строке:

  • V3014 It is likely that a wrong variable is being incremented inside the 'for' operator. Consider reviewing 'i'. EFCore ExpressionEqualityComparer.cs 214
  • V3015 It is likely that a wrong variable is being compared inside the 'for' operator. Consider reviewing 'i' EFCore ExpressionEqualityComparer.cs 214

Это, кстати, не редкая ситуация, когда анализатор выдаёт 2, а иногда даже 3 предупреждения на одну ошибку. Все дело в том, что некорректный код может быть аномален сразу с нескольких точек зрения.

Рассмотрим код:

var memberInitExpression = (MemberInitExpression)obj;
....
for (var i = 0; i < memberInitExpression.Bindings.Count; i++)
{
  var memberBinding = memberInitExpression.Bindings[i];
  .... 
  switch (memberBinding.BindingType)
  {
    case ....
    case MemberBindingType.ListBinding:
      var memberListBinding = (MemberListBinding)memberBinding;
      for(var j=0; i < memberListBinding.Initializers.Count; i++)
      {
        hashCode += (hashCode * 397) ^
          GetHashCode(memberListBinding.Initializers[j].Arguments);
      }
      break;
    ....
   }
}

Что же здесь происходит? Как мы видим, у нас есть 2 цикла. В первом используется счетчик с именем i для обхода списка memberInitExpression.Bindings, во втором - с именем j для обхода списка memberListBinding.Initializers. Но по какой-то причине во втором цикле используется счетчик из первого цикла. Мне это место сразу показалось очень подозрительным, поэтому было решено написать небольшой юнит-тест, чтобы проверить, действительно ли это ошибка, или хитрый алгоритм программы.

Код юнит теста:

[ConditionalFact]
public void Compare_member_init_expressions_by_hash_code()
{
    MethodInfo addMethod = typeof(List<string>).GetMethod("Add");

    MemberListBinding bindingMessages = Expression.ListBind(
        typeof(Node).GetProperty("Messages"),
        Expression.ElementInit(addMethod, Expression.Constant(
          "Greeting from PVS-Studio developers!"))
    );

    MemberListBinding bindingDescriptions = Expression.ListBind(
        typeof(Node).GetProperty("Descriptions"),
        Expression.ElementInit(addMethod, Expression.Constant(
          "PVS-Studio is a static code analyzer for C, C++ and C#."))
    );

    Expression query1 = Expression.MemberInit(
        Expression.New(typeof(Node)),
        new List<MemberBinding>() {
            bindingMessages                    // One member
        }
    );

    Expression query2 = Expression.MemberInit(
        Expression.New(typeof(Node)),
        new List<MemberBinding>() {
            bindingMessages,                  // Two members
            bindingDescriptions
        }
    );

    var comparer = new ExpressionEqualityComparer();
    var key1Hash = comparer.GetHashCode(query1);
    var key2Hash = comparer.GetHashCode(query2);

    // The hash codes for both expressions 
    // were the same before my edit
    Assert.NotEqual(key1Hash, key2Hash);      // <=
}

Мои ожидания подтвердились. Это настоящая ошибка. Дело в том, что при сравнении 2 выражений (Expression's) всегда сравнивались только первые элементы 2 коллекций, что приводило к некорректному результату для разных выражений с одинаковыми первыми элементами. Учитывая тот факт, что Entity Framework очень тесно работает с выражениями, и практически основная его цель - это преобразование лямбд и Linq запросов в SQL запросы, думаю, несложно догадаться, к чему могла приводить столь серьезная ошибка в коде.

Согласно Common Weakness Enumeration найденную ошибку можно классифицировать как CWE-670 (Always-Incorrect Control Flow Implementation). Неизвестно, можно ли эксплуатировать данную слабость кода как уязвимость, но баг достаточно серьезный. Это хорошая демонстрация, что анализатор PVS-Studio можно использовать для поиска потенциальных уязвимостей. На самом деле он всегда это мог, просто мы не акцентировали на этом внимание. Подробнее эта тема раскрыта в статье "PVS-Studio: поиск дефектов безопасности".

Популярные статьи по теме
Насколько хорошо защищены ваши пароли? Проверка проекта Bitwarden

Дата: 13 Май 2022

Автор: Никита Паневин

Bitwarden – менеджер паролей с открытым исходным кодом. Это программное обеспечение помогает генерировать уникальные пароли и управлять ими. Получится ли у анализатора PVS-Studio отыскать ошибки в та…
Зачем разработчикам игр на Unity использовать статический анализ?

Дата: 11 Май 2022

Автор: Артём Ровенский

С годами стоимость создания игр стала больше, вырос их масштаб, а следовательно, и их кодовая база. Разработчикам становится всё сложнее уследить за ошибками. А забагованная игра влечёт финансовые и …
Эволюция PVS-Studio: анализ потока данных для связанных переменных

Дата: 28 Апр 2022

Автор: Никита Липилин

Связанные переменные – одна из главных проблем статического анализа. Данная статья посвящена разбору этой темы и рассказу о том, как разработчики PVS-Studio сражаются с ложными срабатываниями, появив…
Зачем нужен статический анализ? Разбираем на примере ошибки из Akka.NET

Дата: 25 Апр 2022

Автор: Сергей Васильев

"Статический анализ нужно использовать регулярно, а не только перед релизами... Чем раньше найдена ошибка, тем дешевле её исправление..." – вы уже слышали это 100 раз. Сегодня ещё раз ответим на вопр…
Атака Trojan Source: скрытые уязвимости

Дата: 15 Апр 2022

Автор: Гость

Мы представляем новый тип атаки для внедрения в исходный код вредоносных изменений, по-разному выглядящих для компилятора и человека. Такая атака эксплуатирует тонкости стандартов кодирования символо…

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

Следующие комментарии
Этот сайт использует куки и другие технологии, чтобы предоставить вам более персонализированный опыт. Продолжая просмотр страниц нашего веб-сайта, вы принимаете условия использования этих файлов. Если вы не хотите, чтобы ваши данные обрабатывались, пожалуйста, покиньте данный сайт. Подробнее →
Принять