Для получения триального ключа
заполните форму ниже
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: поиск дефектов безопасности".

Последние статьи:

Опрос:

Популярные статьи по теме
Как увеличилась производительность LINQ в .NET 7?

Дата: 30 Ноя 2022

Автор: Михаил Евтихевич

В новой версии .NET улучшилась производительность методов Min, Max, Average и Sum для массивов и списков. Как вы думаете, во сколько раз увеличилась скорость их выполнения? В 2 раза, в 5? Нет, они ст…
Что нового в .NET 7?

Дата: 16 Ноя 2022

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

Вышел .NET 7, а это значит, что можно вдоволь насладиться различными нововведениями и фишками. Расскажем про самые интересные улучшения: C# 11, контейнеры, производительность, GC и прочее.
Что такое катастрофический возврат и как регулярное выражение может стать причиной ReDoS-уязвимости?

Дата: 03 Ноя 2022

Автор: Андрей Москалёв

Регулярные выражения – очень полезный и удобный инструмент для поиска и замены текста. Однако в некоторых случаях они могут привести к зависанию системы или даже стать причиной уязвимости к ReDoS-ата…
Обзор нововведений в C# 11

Дата: 21 Окт 2022

Автор: Константин Волоховский

C# 11 выходит уже совсем скоро, так что пора детально изучить новые особенности, которые появятся в языке. И хотя их немного, среди них есть довольно интересные: обобщённая математика, исходные строк…
Планируете взяться за .NET MAUI? Будьте готовы к приключениям с NullReferenceException

Дата: 06 Окт 2022

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

.NET Multi-platform App UI – фреймворк, который пишут профессионалы. Тем не менее, код некоторых его функций выглядит так, будто разработчики забыли о последствиях разыменования нулевых ссылок.

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

Следующие комментарии
Unicorn with delicious cookie
Мы используем куки, чтобы пользоваться сайтом было удобно.
Хорошо