metrica
Unicorn with delicious cookie
Мы используем куки, чтобы пользоваться сайтом было удобно.
Хорошо
to the top
close form

Заполните форму в два простых шага ниже:

Ваши контактные данные:

Шаг 1
Поздравляем! У вас есть промокод!

Тип желаемой лицензии:

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

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

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

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

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

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


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

>
>
>
История о том, как PVS-Studio нашёл оши…

История о том, как PVS-Studio нашёл ошибку в библиотеке, используемой в... PVS-Studio

08 Авг 2019

Это небольшая история о том, как с помощью PVS-Studio удалось найти ошибку в исходном коде библиотеки, используемой в PVS-Studio. Причём не теоретическую, а фактическую - ошибка проявлялась на практике при использовании библиотеки в анализаторе.

0654_CMDParserBug_ru/image1.png

В PVS-Studio_Cmd (а также некоторых других утилитах) мы используем специальную библиотеку для разбора аргументов командной строки - CommandLine.

Сегодня я занимался поддержкой нового режима в PVS-Studio_Cmd, и как раз так получилось, что пришлось использовать эту библиотеку разбора аргументов. В процессе написания кода также отлаживаю его, так как приходится работать с незнакомыми API.

Итак, код написан, компилируется, запускаю на исполнение, иии...

0654_CMDParserBug_ru/image2.png

Исполнение кода переходит внутрь библиотеки, где возникает исключение типа NullReferenceException. Со стороны не очень понятно - явных никаких нулевых ссылок в метод я не передаю.

На всякий случай смотрю комментарии к вызываемому методу. Очень маловероятно, что в них описаны условия возникновения исключения типа NullReferenceException (так как обычно, как мне кажется, исключения этого типа - непредусмотренные).

0654_CMDParserBug_ru/image3.png

В комментариях к методу информации ни о каком NullReferenceException нет (что, впрочем, ожидаемо).

Чтобы посмотреть, из-за чего конкретно возникает исключение (и где), решил загрузить исходный код проекта, собрать и подключить к анализатору отладочную версию библиотеки. Исходный код проекта доступен на GitHub. Необходима версия 1.9.71, так как именно такая сейчас используется в анализаторе.

Загружаю соответствующую версию исходного кода, собираю, подключаю отладочную библиотеку к анализатору, запускаю код на исполнение и вижу:

0654_CMDParserBug_ru/image4.png

Итак, место возникновения исключения понятно - helpInfo имеет значение null, из-за чего возникает исключение типа NullReferenceException при обращении к экземплярному свойству Left.

И тут я призадумался. В последнее время PVS-Studio для C# был неплохо улучшен в различных областях, в том числе - в области поиска разыменования потенциально нулевых ссылок. В частности - был порядком улучшен межпроцедурный анализ. Поэтому мне сразу же стало интересно проверить исходный код, чтобы понять, сможет ли PVS-Studio найти обсуждаемую ошибку.

Я проверил исходный код, и среди прочих предупреждений увидел именно то, на которое надеялся.

Предупреждение PVS-Studio: V3080 Possible null dereference inside method at 'helpInfo.Left'. Consider inspecting the 2nd argument: helpInfo. Parser.cs 405

Да, вот оно! Именно то, что нужно. Посмотрим на исходный код чуть детальнее.

private bool DoParseArgumentsVerbs(
  string[] args, object options, ref object verbInstance)
{
  var verbs 
    = ReflectionHelper.RetrievePropertyList<VerbOptionAttribute>(options);
  var helpInfo 
    = ReflectionHelper.RetrieveMethod<HelpVerbOptionAttribute>(options);
  if (args.Length == 0)
  {
    if (helpInfo != null || _settings.HelpWriter != null)
    {
      DisplayHelpVerbText(options, helpInfo, null); // <=
    }

    return false;
  }
  ....
}

Анализатор выдаёт предупреждение на вызов метода DisplayHelpVerbText и предупреждает о втором аргументе - helpInfo. Обратите внимание, что этот метод находится в then-ветви оператора if. Условное выражение составлено таким образом, что then-ветвь может быть исполнена при следующих значениях переменных:

  • helpInfo == null;
  • _settings.HelpWriter != null;

Посмотрим тело метода DisplayHelpVerbText:

private void DisplayHelpVerbText(
  object options, Pair<MethodInfo, 
  HelpVerbOptionAttribute> helpInfo, string verb)
{
  string helpText;
  if (verb == null)
  {
    HelpVerbOptionAttribute.InvokeMethod(options, helpInfo, null, out helpText);
  }
  else
  {
    HelpVerbOptionAttribute.InvokeMethod(options, helpInfo, verb, out helpText);
  }

  if (_settings.HelpWriter != null)
  {
    _settings.HelpWriter.Write(helpText);
  }
}

Так как verb == null (см. вызов метода) нас интересует then-ветвь оператора if. Хотя с else ветвью ситуация будет аналогична, рассматривать будем then-ветвь, так как в нашем частном случае именно через неё шло исполнение. Помним, что helpInfo может иметь значение null.

Теперь посмотрим на тело метода HelpVerbOptionAttribute.InvokeMethod. Собственно, его вы уже видели на скриншоте выше:

internal static void InvokeMethod(
    object target,
    Pair<MethodInfo, HelpVerbOptionAttribute> helpInfo,
    string verb,
    out string text)
{
  text = null;
  var method = helpInfo.Left;
  if (!CheckMethodSignature(method))
  {
    throw new MemberAccessException(
      SR.MemberAccessException_BadSignatureForHelpVerbOptionAttribute
        .FormatInvariant(method.Name));
  }

  text = (string)method.Invoke(target, new object[] { verb });
}

helpInfo.Left вызывается безусловно, при том, что helpInfo может иметь значение null. Об этом предупреждал анализатор, это и произошло.

Заключение

Забавно получилось, что с помощью PVS-Studio удалось найти ошибку в коде библиотеки, которая используется в PVS-Studio. Я думаю, это своего рода продолжение ответа на вопрос "Находит ли PVS-Studio ошибки в коде PVS-Studio?". :) Может находить ошибки не только в коде PVS-Studio, но и в коде используемых библиотек.

Напоследок предложу скачать анализатор и попробовать проверить свой проект - вдруг и там удастся найти что-нибудь интересное?

Популярные статьи по теме
Уязвимость XSS в приложении ASP.NET: разбираем CVE-2023-24322 в CMS mojoPortal

Дата: 31 Май 2023

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

В этой статье изучим с разных сторон уязвимость XSS в CMS, написанной на C#. Вспомним теорию, разберёмся, как дефект безопасности выглядит со стороны пользователя и кода, а также поупражняемся в сост…
RavenDB и PVS-Studio: коллаборация, от которой выигрывают все

Дата: 24 Май 2023

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

Небольшая история про сотрудничество PVS-Studio и RavenDB. PVS-Studio — статический анализатор для улучшения кода. RavenDB — Open Source база данных. Как поиск ошибок в одном проекте приводит к улучш…
BTCPay Server: топ-10 ошибок в коде финансового приложения для Bitcoin

Дата: 17 Май 2023

Автор: Святослав Размыслов

Наша компания пишет много материалов на тему качества кода. Некоторые проекты, выбранные для аудита кода, не очень близки всем читателям, но все из вас точно пользуются финансовыми приложениями. Може…
Топ-10 докладов на С# конференциях 2019-2022 года

Дата: 10 Май 2023

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

Небольшая подборка интересных докладов с конференций для C# и .NET разработчиков за последние несколько лет.
NullReferenceException в C#. Что это такое и как исправить?

Дата: 02 Май 2023

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

NullReferenceException (NRE) — тип исключения платформы .NET, возникающий при попытке обращения по нулевой ссылке. В заметке рассмотрим причины, из-за которых возникают исключения этого типа, а также…


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

Следующие комментарии next comments
close comment form