Для получения триального ключа
заполните форму ниже
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. Новый триальный режим позволяет видеть все обнаруженные проблемы.

Популярные статьи по теме
Интервью с Джейсоном Тернером, одним из ведущих подкаста "CppCast": история и причины закрытия проекта

Дата: 27 Сен 2022

Автор: Ульяна Гришина

В этой статье мы поговорим с Джейсоном Тернером, одним из основателей CppCast. CppCast – это первый С++ подкаст, основанный С++ разработчиками. Начиная с 2015 года каждую неделю на CppCast выходили п…
Боремся с 16-летним легаси-кодом, или исправляем C и C++ front-end в PVS-Studio

Дата: 22 Сен 2022

Автор: Сергей Ларин

В 2022 году статическому анализатору PVS-Studio для языков C и C++ исполняется 16 лет. Если бы анализатор был человеком, то он бы уже заканчивал школу. Это очень старый проект, и система типов в нем …
Как фидбек помог улучшить наш C++ квиз

Дата: 31 Авг 2022

Автор: Алексей Саркисов

Ранее в нашем блоге мы рассказывали о квизе для C++ разработчиков. С момента запуска мы тщательно собирали обратную связь. Часть из неё касалась ошибок в работе квиза, которые мы естественно решили и…
Концепция умного указателя static_ptr<T> в C++

Дата: 30 Авг 2022

Автор: Гость

В C++ есть несколько "умных указателей" – 'std::unique_ptr', 'std::shared_ptr', 'std::weak_ptr'.
"Так исторически сложилось", или за что разделили V512

Дата: 12 Авг 2022

Автор: Михаил Гельвих

Как говорится, в любом деле самое сложное — это начать. Так и мы, очень долго откладывали разделение диагностики V512, но время пришло. Ну а о причинах и последствиях этого решения можно прочитать в …

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

Следующие комментарии
Unicorn with delicious cookie
Мы используем куки, чтобы пользоваться сайтом было удобно. Хотите узнать подробнее?
Принять