Для получения триального ключа
заполните форму ниже
Team License (базовая версия)
Enterprise License (расширенная версия)
* Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности

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

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

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

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

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

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


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

>
>
>
Проверка проекта Dolphin-emu

Проверка проекта Dolphin-emu

24 Фев 2012

Нам регулярно предлагают проверить различные открытые проекты с помощью анализатора PVS-Studio. Если вы тоже хотите предложить что-то для проверки, то прошу перейти по этой ссылке. Очередным проектом стал проект Dolphin-emu.

Введение

Dolphin-emu это эмулятор Gamecube и Wii. Так как это проект с открытыми исходными кодами, любой может вносить улучшения. Код размещен на GitHub.

Мы нашли в этом проекте совсем мало ошибок. В первую очередь это связанно с тем, что это небольшой по объему проект. Размер проекта составляет около 260 000 строк кода. Оставшуюся часть проекта (1340 000 строк кода) составляют сторонние библиотеки, которые тестировать не так интересно.

Хотя ошибок выявлено мало, о некоторых фрагментах кода можно рассказать в статье. С остальными опасными участками кода разработчики смогут познакомиться самостоятельно, воспользовавшись триальной версией PVS-Studio.

Опечатки

Опечатки коварны и их можно встретить в любом приложении. Программисты уверены, что допускают только сложные ошибки и анализаторы в первую очередь должны искать утечки памяти и ошибки синхронизации. К сожалению, реальность намного банальнее и самыми распространенными ошибками являются опечатки и неправильно скопированные участки кода. Например, в Dolphin-emu есть такая функция:

bool IRBuilder::maskedValueIsZero(
  InstLoc Op1, InstLoc Op2) const
{
  return (~ComputeKnownZeroBits(Op1) &
          ~ComputeKnownZeroBits(Op1)) == 0;
}

Сообщение анализатора PVS-Studio:

V501 There are identical sub-expressions '~ComputeKnownZeroBits(Op1)' to the left and to the right of the '&' operator. Core ir.cpp 1215

Из-за опечатки два раза используется переменная 'Op1' и ни разу не используется 'Op2'. А вот другой пример, где не там поставлена закрывающаяся круглая скобка ')'.

static const char iplverPAL[0x100] = "(C) 1999-2001 ....";
static const char iplverNTSC[0x100]= "(C) 1999-2001 ....";
CEXIIPL::CEXIIPL() : ....
{
  ...
  memcpy(m_pIPL, m_bNTSC ? iplverNTSC : iplverPAL,
         sizeof(m_bNTSC ? iplverNTSC : iplverPAL));
  ...
}

Предупреждение PVS-Studio:

V568 It's odd that the argument of sizeof() operator is the 'm_bNTSC ? iplverNTSC : iplverPAL' expression. Core exi_deviceipl.cpp 112

Выражение внутри оператора sizeof() не вычисляется. Этот код работает только благодаря тому, что типы массивов 'iplverNTSC' и 'iplverPAL' совпадают. Получается, что sizeof() всегда возвращает 0x100. Это интересный момент. Если бы размер массива 'iplverNTSC' и 'iplverPAL ' отличался, то всё бы работало совсем по-другому. Рассмотрим тестовый пример для наглядности:

const char A[10] = "123";
const char B[10] = "123";
const char C[20] = "123";
cout << sizeof(true ? A : B) << ", "
     << sizeof(true ? A : C) << endl;

Результат работы программы: 10, 4.

В первом случае печатается размер массива, а во втором - размер указателя.

Ошибки низкоуровневой работы с памяти

Помимо опечаток очень часто встречаются ошибки работы с такими функциями как memset() и memcpy().

u32 Flatten(..., BlockStats *st, ...)
{
  ...
  memset(st, 0, sizeof(st));
  ...
}

Предупреждение PVS-Studio:

V579 The memset function receives the pointer and its size as arguments. It is possibly a mistake. Inspect the third argument. Core ppcanalyst.cpp 302

Случайно вычисляется размер указателя на объект, а не размер самого объекта BlockStats. Правильный вариант: sizeof(*st).

А вот другая аналогичная ситуация:

void drawShadedTexSubQuad(...,
  const MathUtil::Rectangle<float>* rDest, ...)
{
  ...
  if (stsq_observer ||
      memcmp(rDest,
        &tex_sub_quad_data.rdest, sizeof(rDest)) != 0 ||
      tex_sub_quad_data.u1 != u1 ||
      tex_sub_quad_data.v1 != v1 ||
      tex_sub_quad_data.u2 != u2 ||
      tex_sub_quad_data.v2 != v2 ||
      tex_sub_quad_data.G != G)
  ...
}

Сравнивается только часть структуры. Правильный вариант: sizeof(*rDest).

Работа с float

В некоторых местах проекта Dolphin-emu, работа с переменными типа float, выглядит излишне оптимистично. Переменные типа float сравниваются с помощью операторов == и !=. Подобные сравнения допустимы только в определенных случаях. Более подробно о сравнении переменных типа float можно познакомиться в документации к диагностическому правилу V550. Рассмотрим пример:

float Slope::GetValue(float dx, float dy)
{
  return f0 + (dfdx * dx) + (dfdy * dy);
}

void BuildBlock(s32 blockX, s32 blockY)
{
  ...
  float invW = 1.0f / WSlope.GetValue(dx, dy);
  ...
  float q = TexSlopes[i][2].GetValue(dx, dy) * invW;
  if (q != 0.0f)
    projection = invW / q;
  ...
}

Предупреждение PVS-Studio

V550 An odd precise comparison: q != 0.0f. It's probably better to use a comparison with defined precision: fabs(A - B) > Epsilon. VideoSoftware rasterizer.cpp 264

Обратите внимание на сравнение "if (q != 0.0f)". Как видно из кода, переменная 'q' вычисляется достаточно сложным образом. И как следствие, практически невероятно, что она ТОЧНО будет равна нулю. Скорее всего, переменная может получить, например значение 0.00000002. Это не 0, но деление на такое маленькое число может привести к переполнению. Необходима специальная проверка на подобные случаи.

Насилие над строками

void CMemoryWindow::onSearch(wxCommandEvent& event)
{
  ...
  //sprintf(tmpstr, "%s%s", tmpstr, rawData.c_str());
  //strcpy(&tmpstr[1], rawData.ToAscii());
  //memcpy(&tmpstr[1], &rawData.c_str()[0], rawData.size());
  sprintf(tmpstr, "%s%s", tmpstr, (const char *)rawData.mb_str());
  ...
}

Из закомментированного кода видно, что это больное место. Это уже четвертая попытка сформировать строку. К сожалению, она тоже далека от идеала. Анализатор PVS-Studio предупреждает:

V541 It is dangerous to print the string 'tmpstr' into itself. Dolphin memorywindow.cpp 344

Опасность заключается в том, что строка "tmpstr" печатается в саму себя. Этот код может корректно работать, но так лучше не делать. В зависимости от реализации функции sprintf() можно неожиданно получить некорректный результат. Возможно, здесь более уместно было бы использовать функцию strcat().

Есть и другие участки кода, которые хотя и работают, но весьма потенциально опасны:

V541 It is dangerous to print the string 'pathData_bin' into itself. Dolphin wiisavecrypted.cpp 513

V541 It is dangerous to print the string 'regs' into itself. Core interpreter.cpp 84

V541 It is dangerous to print the string 'fregs' into itself. Core interpreter.cpp 89

Заключение

Вы можете сами посмотреть на эти и другие ошибки, скачав PVS-Studio. Новый триальный режим позволяет видеть все обнаруженные проблемы.

Популярные статьи по теме
Как различить C и C++ разработчиков по их коду

Дата: 12 Май 2022

Автор: Гость

Так уж случилось, что я пишу код для разных IoT-железок, связанных с электричеством, типа зарядных станций автомобилей. Поскольку аппаратных ресурсов, как правило, вполне достаточно, то основным фоку…
Отладочный вывод на микроконтроллерах: как Concepts и Ranges отправили мой printf на покой

Дата: 06 Май 2022

Автор: Гость

Здравствуйте! Меня зовут Александр, и я работаю программистом микроконтроллеров.
Нереальный baselining или доработки PVS-Studio для Unreal Engine проектов

Дата: 26 Апр 2022

Автор: Валерий Комаров

Статический анализатор PVS-Studio постоянно развивается: улучшаются различные механизмы, происходит интеграция с игровыми движками, IDE, CI/CD и другими системами и сервисами. Благодаря этому несколь…
Разбор некоторых вредных советов для С++ программиста

Дата: 21 Апр 2022

Автор: Андрей Карпов

Юмор юмором, но осторожность не повредит. Вдруг кому-то не до конца понятно, почему какой-то из советов является вредным. Здесь можно найти соответствующие пояснения.
Четыре причины проверять, что вернула функция malloc

Дата: 20 Апр 2022

Автор: Андрей Карпов

Некоторые разработчики пренебрежительно относятся к проверкам: удалось ли выделить память с помощью функции malloc или нет. Их логика проста – памяти всегда должно хватить. А если не хватит, всё равн…

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

Следующие комментарии
Этот сайт использует куки и другие технологии, чтобы предоставить вам более персонализированный опыт. Продолжая просмотр страниц нашего веб-сайта, вы принимаете условия использования этих файлов. Если вы не хотите, чтобы ваши данные обрабатывались, пожалуйста, покиньте данный сайт. Подробнее →
Принять