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, и может в фоновом режиме выполнять анализ измененных файлов после их компиляции. В идеале ошибки будут обнаружены и исправлены ещё до попадания в репозиторий. Однако ничто не мешает использовать анализатор для проверки всего решения целиком или для встраивания в системы непрерывной интеграции. Эти и иные способы использования анализатора описаны в документации.
Ищем ошибки в игровом движке Xenko
Запись от el_programmer размещена 11.03.2016 в 09:54
Показов 3152
Комментарии 1
Метки c#, csharp, gamedev, open source, programming, xenko
|
Ищем ошибки в игровом движке Xenko Автор: Васильев Сергей Движков с открытым исходным кодом, написанных на C++, куда больше, чем аналогичных движков, написанных на C#. Но есть исключения. Xenko – один из движков, написанных на C# и имеющих открытый исходный код. О том, что же интересного удалось найти в коде этого движка, будет рассказано в этой статье. Анализируемый проект Xenko (ранее известный как Paradox) - кроссплатформенный игровой движок, позволяющий разрабатывать игры, используя для этого язык программирования C#. Движок позволяет разрабатывать как 2D, так и 3D-игры под разные платформы: Android, iOS, Windows Desktop, Windows Phone, PlayStation 4. В будущем также планируется поддержка MacOSX и Linux. Исходный код движка доступен в репозитории на GitHub. Большая часть кода (89% по информации с GitHub), написана на C#. Инструмент анализа Проект проверялся с помощью анализатора PVS-Studio. Помимо уже привычных ошибок (вроде V3001), в нём обнаружились подозрительные фрагменты кода, диагностируемые правилами из последнего релиза анализатора. Все диагностические сообщения содержат документацию, в которой приводятся примеры ошибок, их описание, а также способы их исправления. Дабы не быть голословным, предлагаю посмотреть, что же нашлось интересного. Подозрительные фрагменты кода Часто ошибки ведут к более серьёзным последствиям, чем кажется на первый взгляд. Для того, чтобы лучше понять их суть и способы исправления, рекомендую ознакомиться с документацией к диагностическим правилам.
Часто люди думают: "Ну, проверили два раза условие, ничего страшного в этом нет". На первый взгляд - да, и порой это действительно так. Но чаще проблема заключается в ином - условие перепутали, следовательно, допущена логическая ошибка и логика программы не соответствует задуманной. Так же и здесь. Два раза выполняется проверка подусловия за счёт вызова метода 'SupportFormat(converting.Format)', но скорее всего во втором случае подразумевался вызов следующего вида: 'SupportFormat(image.Format)'. Тогда всё выражение примет вид:
В коде, приведённом в статье, ошибку видно невооружённым глазом. А вот в файле с этим кодом она, мягко говоря, не бросается в глаза. Отчасти в этом "заслуга" форматирования - в файле это выражение записано в одну строку, так что дублирование подвыражений без детального просмотра кода можно и не заметить. Думаю, подразумевался другой элемент перечисления, например, 'BSpline'. Вообще в больших выражениях достаточно легко допустить подобную ошибку, как это будет видно на следующем примере. Попробуйте найти ошибку самостоятельно, не читая предупреждения анализатора и пояснений к коду:
Разобраться в таком коде явно непросто... Давайте попробуем упростить выражение, заменив подвыражение простыми буквами (опустив при этом скобки). Тогда получится следующий код:
Как минимум - условие выглядит странно. Можно было бы предположить, что здесь тоже подразумевалось другое подвыражение, но судя по комментарию - нет. Выходит, это опечатка, хотя не совсем понятно, как её можно было допустить. В любом случае, код необходимо поправить. Нередко ошибаются и в присваиваниях, когда выполняется присваивание объекта самому себе. В подобных случаях, глядя со стороны, бывает сложно сказать, как правильно исправить код. Посмотрим на несколько таких мест:
Поле 'hashCode' присваивается само себе. Как минимум - это лишнее присваивание, но скорее всего в методе хеширования допущена ошибка. Видится несколько вариантов исправления:
Как правильно поступить в данном случае - решать автору кода. В коде встречались выражения, значение которых всегда было истинным или ложным. Подобные случаи выявляет диагностика V3022, и дальше будут приведены некоторые фрагменты кода, которые удалось обнаружить с её помощью.
В тернарном операторе переменная 'moveNextFrame' всегда будет иметь значение 'true'. В ином случае будет осуществлён выход из цикла до выполнения рассматриваемого оператора. Таким образом, если выполнение всё же дойдёт до тернарного оператора, то объект 'keyFrame' всегда будет иметь одно и то же значение - 'currentKeyFrame.Current'. Предупреждения для фрагментов кода, в которых прослеживается схожая ситуация:
Продолжим обзор:
Данное выражение или избыточно, или содержит ошибку. Если истинно первое подвыражение, то второе подвыражение также всегда будет истинным (впрочем, до его вычисления выполнение не дойдёт). Данное выражение можно упростить до 'diff3.ChangeType != Diff3ChangeType.None'. Скорее всего, в рассматриваемом случае реализована просто излишняя проверка, хотя в некоторых случаях это может свидетельствовать об иной ошибке - когда проверяется не та переменная. Подробнее об этом написано в документации к диагностике. Нашлась пара интересных мест со строками форматирования:
Параметры строки форматирования индексируются с {0}, здесь же индексация начинается с {1}. В данном случае строка форматирования ожидает 4 аргумента, но представлены только 3, из-за чего будет сгенерировано исключение типа 'FormatException'. Для исправления данной ошибки необходимо правильно пронумеровать индексы в строке форматирования.
С точностью противоположная ситуация - строка форматирования требует наличия 1 аргумента, однако метод содержит 2 - 'item' и 'text'. В данном случае ненужный аргумент попросту будет проигнорирован, но такой код должен навести на подозрения. В лучшем случае второй аргумент просто является лишним и его можно удалить, в худшем - строка форматирования составлена ошибочно.
Этот цикл ожидает некого события извне и должен выполняться до тех пор, пока переменная 'requestedExit' имеет значение 'false'. Однако после оптимизации данный цикл может превратиться в бесконечный из-за того, что компилятор может закешировать значение переменной 'requestedExit'. Данные ошибки достаточно трудно отлавливаемы, так как именно из-за кеширования, проводимого при оптимизации, поведение программы 'Debug' и 'Release' версиях может отличаться. Для исправления ошибки можно добавить модификатор 'volatile' при объявлении поля или же использовать специализированные средства синхронизации. Подробнее об этом можно прочитать в документации к данной диагностике. Следующий странный фрагмент кода:
Сразу хочу сказать, что переменная 'pivotValue', кроме как в приведённом фрагменте нигде не используется. Данная переменная имеет тип 'double', однако при её инициализации будет производится целочисленное деление, так как типы всех переменных, участвующих в инициализирующем выражении - целочисленные. Более того, далее выполняется обратное приведение данной переменной обратно к типу 'int'. Таким образом, можно было бы сразу использовать тип 'int' при объявлении переменной 'pivotValue', или же использовать инициализирующее выражение для вычисления индекса массива. Так или иначе, код выглядит странно и его стоит упростить. Следующее предупреждение связано с подсистемой WPF:
При регистрации свойства зависимости было указано, что свойство хранит значение типа 'object'. Таким образом, в данное свойство может быть записано значение любого типа, однако при попытке обращения к нему возможно возникновение исключения в случае, если тип объекта, записанного в свойство, невозможно привести к типу 'Key'. О том, что при регистрации свойства в качестве хранимого типа необходимо задать 'Key' свидетельствует и то, что в качестве значения по умолчанию для свойства указано значение 'Key.Enter'. Новые диагностические правила Как я упоминал в начале статьи, в проекте удалось обнаружить места, выявленные новыми диагностическими сообщениями, добавленными в последнем релизе PVS-Studio. Обзор некоторых таких мест приведён ниже. Встретилось несколько фрагментов кода, в которых один из параметров метода перезаписывался, но перед этим его значение никак не использовалось. Таким образом, значение, пришедшее в метод, попросту теряется:
Данный код выглядит странно, так как объект 'internalEvent' нигде не используется, сразу же перезаписывается, после чего возвращается из метода. Тогда из сигнатуры метода вообще можно было бы убрать этот параметр, а тело метода упростить до следующего вида:
Встретились ещё 2 случая с перезаписью параметра:
Параметр 'libraryData' перезаписывается до того, как его значение где-то используется. При этом он не отмечен модификаторами 'ref' или 'out'. Это очень странно, так как значение, принимаемое методом, попросту теряется. Предупреждение, выданное на схожий код: V3061 Parameter 'libraryData' is always rewritten in method body before being used. SiliconStudio.TextureConverter FITexLib.cs 244 Противоположная ситуация - метод принимает аргумент, значение которого не используется:
Как видно из предупреждения анализатора, параметр 'height' нигде не используется. Вместо него в метод 'CreateDescription' дважды передаётся параметр 'width', что может свидетельствовать о наличии ошибки. Правильный вызов метода 'CreateDescription' может выглядеть так:
Заключение Было интересно проверить игровой движок, написанный на C#. Все допускают ошибки, и различные инструменты позволяют минимизировать их количество, и статический анализатор - один из таких инструментов. И чем раньше будет найдена ошибка, тем дешевле обойдётся её исправление. Конечно, не все ошибки, найденные в проекте, были выписаны в статье. Во-первых, это сильно бы увеличило размер статьи, во-вторых - некоторые из диагностических сообщений являются специфичными, т.е. актуальными для определённых типов проектов, поэтому могут быть интересны не всем. Но, безусловно, разработчикам (а возможно и просто любопытным программистам) будет интересно посмотреть все подозрительные места, найденные анализатором. Это можно сделать, загрузив пробную версию анализатора. | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Метки c#, csharp, gamedev, open source, programming, xenko
Размещено в Без категории
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Всего комментариев 1
Комментарии
-
Собственно ссылка на источник: https://habrahabr.ru/company/p... og/278881/Запись от Eva Rosalene размещена 12.03.2016 в 00:40


