PVS-Studio - это инструмент для выявления ошибок в исходном коде программ, написанных на языках С, C++ и C#.
PVS-Studio выполняет статический анализ кода и генерирует отчёт, помогающий программисту находить и устранять ошибки. PVS-Studio выполняет широкий спектр проверок кода, но наиболее силён в поисках опечаток и последствий неудачного Copy-Paste. Показательные примеры таких ошибок: V501, V517, V522, V523, V3001.
Анализатор ориентирован на разработчиков, использующих среду Visual Studio, и может в фоновом режиме выполнять анализ измененных файлов после их компиляции. В идеале ошибки будут обнаружены и исправлены ещё до попадания в репозиторий. Однако ничто не мешает использовать анализатор для проверки всего решения целиком или для встраивания в системы непрерывной интеграции. Эти и иные способы использования анализатора описаны в документации.
PVS-Studio выполняет статический анализ кода и генерирует отчёт, помогающий программисту находить и устранять ошибки. PVS-Studio выполняет широкий спектр проверок кода, но наиболее силён в поисках опечаток и последствий неудачного Copy-Paste. Показательные примеры таких ошибок: V501, V517, V522, V523, V3001.
Анализатор ориентирован на разработчиков, использующих среду Visual Studio, и может в фоновом режиме выполнять анализ измененных файлов после их компиляции. В идеале ошибки будут обнаружены и исправлены ещё до попадания в репозиторий. Однако ничто не мешает использовать анализатор для проверки всего решения целиком или для встраивания в системы непрерывной интеграции. Эти и иные способы использования анализатора описаны в документации.
Проверяем исходный код плагина PVS-Studio с помощью PVS-Studio
Запись от el_programmer размещена 16.03.2016 в 16:57
Показов 2606
Комментарии 0
Метки c#, csharp, programming, pvs-studio, ошибки
|
Автор: Виталий Алферов Один из вечных вопросов, с которыми мы встречаемся, звучит так - "Вы проверяли PVS-Studio с помощью PVS-Studio? Где статья о результатах проверки?". Да, мы регулярно делаем это, поэтому мы никак не могли написать статью об ошибках, которые нашли сами в себе. Ошибки исправляются разработчиками ещё на этапе написания кода, и мы постоянно забываем в этот момент их выписать. Но читателям в этот раз повезло. Из-за недосмотра C# код плагина для Visual Studio не был добавлен в ежедневные ночные проверки, которые мы проводим. И, соответственно, в отличие от ядра анализатора, ошибки в нем не замечались на протяжении всего развития C# PVS-Studio. Как говорится, нет худа без добра, и благодаря этому вы и читаете данную статью. Чуть подробнее о тестировании PVS-Studio Возможно, читателям интересно будет узнать, как вообще построен процесс тестирования PVS-Studio. Мы уже писали статью на эту тему. Но с тех времён прошло много времени, и кое-что изменилось. Поэтому кратко опишу, как обстоят дела на данный момент. Разрабатывая PVS-Studio, мы используем семь методик тестирования:
Как же так получилось, что мы упустили проверку плагина? Сами не знаем. Просто никто не вспомнил добавить на сервере проверку кода плагина. Проверку нового C# анализатора добавили, а плагина - нет. В результате C# анализатор развивался и находил ошибки сам в себе. А плагин, также написанный на C#, остался в стороне. Он практически не изменялся за последнее время. Вот и вышло, что инкрементальный анализ не помог, так как с кодом плагина почти не работали. А ночных проверок не было. PVS-Studio Plugin В силу своей честности и открытости перед клиентами и дабы избежать разговоров а-ля - "В чужом глазу соринку видите, а в своем бревно не заметите", мы распишем все наши опечатки и ошибки вплоть до курьёзных. Всем найденным ошибкам мы обязаны анализатору PVS-Studio v6.02, поддерживающему C#. Начнем, пожалуй, с реальных ошибок, которые к моменту написания этих строк уже исправлены.
V3022 Expression 'RowsCount > 100000' is always false. ProcessingEngine.cs 559 V3022 Expression 'RowsCount > 200000' is always false. ProcessingEngine.cs 561 Человеческий мозг привык думать последовательно - от простого к сложному или, как в данном случае, от меньшего к большему, проверяя все значения. В данном случае подобная логика человека привела к неправильному поведению программы. Ошибка возникла при проверке количества строк в таблице. Программа, проверив первое условие, что строк больше чем 20000, сразу присвоит DatatableUpdateInterval значение в 30 секунд. И, естественно, не станет проверять остальные условия. Даже если RowsCount был 1000000. Данный код был написан с целью оптимизации вывода сообщений об ошибках в IDE окно PVS-Studio в Visual Studio. Изначально плагин PVS-Studio выдавал результаты анализа сразу по получению. То есть в тот момент, когда эти результаты приходили из процесса cmd (который запускает ядро анализатора). Однако на очень больших проектах мы стали замечать серьёзные "тормоза" интерфейса. Особенно проблемы проявлялись, когда в проектах присутствовало большое количество *.c файлов. Это происходило потому, что *.c файлы проверялись очень быстро, и UI поток оказывался постоянно занят перерисовкой таблицы результатов. Было принято решение добавить задержку между обновлениями, которая увеличивалась бы с ростом числа сообщений. До достижения 20000 сообщений в списке задержка выставлялась в 15 секунд. В данном случае нам повезло, и мы получим лишь небольшое замедление в программе (тем более, что очень редко мы получаем больше сотни тысяч сообщений после проверки), но данное сообщение предназначено выявлять и более серьезные случаи. Например, как было в проекте от компании Infragistics.
Следующая ошибка более серьезна для нашего проекта:
Хоть ошибка и имеет иной номер, суть её та же. Логика человека - следовать от простого к сложному, подкачала и здесь. Проверив значение "info.PreprocessorCommandLine" на вхождение в него подстроки " /arch:SSE", мы одновременно будем удовлетворять условию в том случае, когда "info.PreprocessorCommandLine" будет содержать следующую подстроку " /arch:SSE2". Как видите, текст, который естественным образом читается, совершенно не соответствует логике, которую мы хотели задать в программе. Даже если мы будем знать, что в PreprocessorCommandLine содержится "/arch:SSE2", то пройдя глазами по коду мы умозрительно прибавим к переменной ClangCommandLine значение " /D "_M_IX86_FP=2"", а не " /D "_M_IX86_FP=1""; С точки зрения анализатора, ошибка заключалась в некорректном определении макроса _M_IX86_FP при передаче компилятору флага /arch:SSE2. Дело в том, что для препроцессирования перед непосредственно анализом, PVS-Studio использует Clang вместо cl (стандартный препроцессор Visual C++). Clang работает значительно быстрее. К сожалению, поддержка диалекта языка C++ от Microsoft в Clang до сих пор далека от идеала - поэтому, если Clang "не смог" что-то препроцессировать, PVS-Studio позовёт cl. Поэтому мы и преобразуем флаги компилятора cl в define для Clang. Данная ошибка, скорее всего, никогда не приводила к ошибкам в работе Clang или некорректной выдаче результатов анализа, поэтому она очень долго существовала в нашем коде. Еще одной реальной ошибкой является вызов функции ProcessAnalyzerOutput.
V3066 Possible incorrect order of arguments passed to 'ProcessAnalyzerOutput' method: 'strStandardError' and 'strStandardOutput'. ProcessingEngine.cs 1995 В подобном длинном списке параметров функции всегда сложно обнаружить несоответствие. Даже IntelliSense в подобных случаях не всегда спасает. В больших проектах он бывает подтормаживает, и из-за этого не всегда понятно, на каком элементе ты сейчас находишься. Из-за этого может произойти весьма неприятная ситуация. Хотя эта диагностика и относится к третьему уровню, как и все остальные эвристические, но весьма полезна, и не стоит её игнорировать. Место, в котором была выявлена данная ошибка, является "заглушкой" - в параметры stderr и stdout никогда не приходило что-то кроме пустых строк. Данная ошибка обнаружила бы себя достаточно быстро, когда данной заглушкой начали бы пользоваться. Еще одна ошибка была выявлена диагностикой под номером V3072, которая на данный момент находится в разработке:
В данном случае в классе ProcessingEngine (который не унаследован от интерфейса IDisposable) присутствуют поле класса PVSMessageBase, тип которого унаследован от интерфейса IDisposable. Данное срабатывание можно отнести к false positive, вызванным не совсем "опрятной" архитектурой. Класс ProcessingEngine используется в программе как singleton. И поэтому единственный его экземпляр существует в течении всего времени работы программы так же, как и поле PVSMessageBase. Ресурсы будут освобождены после завершения программы. Ну что ж, на зло недоброжелателям и на радость нам, других серьезных ошибок в коде не было найдено. Остальная часть "ошибок" скорее относится к формату - "на всякий случай" Например, вот в таком выражении:
Данный код можно смело сократить до:
Уж если начал перестраховываться, то надо держаться до конца и проверять всё. Как, например, здесь:
Иногда код доходит до "весьма странных приведений", но уж если обещали писать обо всем, то пишем:
V3051 An excessive type cast. The object is already of the 'String' type. TrialExtensionRequest.cs 241 Еще в нашем коде встречаются следующие проверки:
И еще раз:
Ошибочно проверять переменную на null после того, как была вызвана функция Equals. На самом деле настоящей ошибки здесь нет, так как согласно API, в переменных "CompileAsManaged" и "DisableLanguageExtensions" не может быть null. Поэтому проверки можно упростить до:
Проверка переменной buttons на равенство MessageBoxButtons.OKCancel не имеет смысла т.к. в любом случае мы вернем DialogResult.OK. Как следствие, в нашем случае код сокращается до:
Заключение Проверяя свой код, испытываешь разные чувства. Если ошибка сделана собственной рукой, то пытаешься её поправить или найти ей оправдание. Если ошибка у другого, то к ней испытываешь совершенно другой спектр чувств. В этом и состоит большая проблема осознания того, что мы все люди и все мы ошибаемся. Некоторые из нас это признают, и это уже хорошо, некоторые упорствуют: - ... это не ошибки... - ... это легко исправить... - ... 5 лет работало, и никто не жаловался... Да, действительно, многие ошибки легко исправить, и это очень хорошо. Но вот заметить эту опечатку или ошибку бывает очень непросто. Часто ошибку замечает не сам программист, а тестер или, что еще хуже - пользователь. Цель нашего анализатора - помочь вам увидеть эти ошибки и опечатки. Согласитесь, гораздо лучше писать большой текст в Microsoft Word, чем в блокноте. А код программ зачастую больше некоторых нашумевших бестселлеров. PVS-Studio, по факту, и является системой проверки орфографии из Microsoft Word для вашего кода. Он просто подскажет вам, что здесь вы поторопились и опечатались, или, возможно, выразили свою мысль не так, как хотели. Согласитесь - правильное формулирование мысли в тексте книги очень важно для читателя, а правильное формирование логики программы важно для конечного пользователя. Пользуясь PVS-Studio вы сможете гораздо лучше выразить и сформулировать свою мысль. Желаем вам вдохновения и четкой мысли, а мы вам в этом поможем. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Метки c#, csharp, programming, pvs-studio, ошибки
Размещено в Без категории
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Всего комментариев 0
Комментарии


