Хабрахабр

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

Picture 1

Это небольшая история о том, как с помощью PVS-Studio удалось найти ошибку в исходном коде библиотеки, используемой в PVS-Studio. Причём не теоретическую, а фактическую — ошибка проявлялась на практике при использовании библиотеки в анализаторе.
В PVS-Studio_Cmd (а также некоторых других утилитах) мы используем специальную библиотеку для разбора аргументов командной строки — CommandLine.

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

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

Picture 3

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

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

Picture 2

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

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

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

Picture 4

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

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

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

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

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

private bool DoParseArgumentsVerbs( string[] args, object options, ref object verbInstance)
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.

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

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, но и в коде используемых библиотек.

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

The story of how PVS-Studio found an error in the library used in… PVS-Studio Если хотите поделиться этой статьей с англоязычной аудиторией, то прошу использовать ссылку на перевод: Sergey Vasiliev.

Теги
Показать больше

Похожие статьи

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

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

Кнопка «Наверх»
Закрыть