to the top
close form

Заполните форму в два простых шага ниже:

Ваши контактные данные:

Шаг 1
Поздравляем! У вас есть промокод!

Тип желаемой лицензии:

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

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

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

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

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

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


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

>
>
>
Библиотеки Electronic Arts почти хороше…

Библиотеки Electronic Arts почти хорошего качества

29 Июл 2019

Наше внимание привлёк репозиторий Electronic Arts на GitHub. Он очень маленький и из двадцати трёх проектов нас заинтересовали только несколько C++ библиотек: EASTL, EAStdC, EABase, EAThread, EATest, EAMain и EAAssert. Проекты оказались тоже очень маленькими (около 10 файлов), поэтому мы нашли ошибки только в "самом большом" из 20 файлов :D Но нашли, и интересные! Пока писалась заметка, мы с коллегами также бурно обсудили игры компании EA и её стратегию :D.

0646_ElectornicArtsStdC_ru/image1.png

Введение

Electronic Arts (EA) - американская компания, которая занимается распространением видеоигр. На сайте GitHub у неё есть небольшой репозиторий и несколько C++ проектов. Это C++ библиотеки: EASTL, EAStdC, EABase, EAThread, EATest, EAMain и EAAssert. Они очень маленькие и мы нашли интересные ошибки с помощью анализатора PVS-Studio только в "самом большом" из них - EAStdC (20 файлов). При таких объёмах сложно говорить о качестве кода в целом. Просто оцените 5 предупреждений и решите сами.

Предупреждение 1

V524 It is odd that the body of '>>' function is fully equivalent to the body of '<<' function. EAFixedPoint.h 287

template <class  T,
  int  upShiftInt, int downShiftInt,
  int  upMulInt,   int downDivInt>

struct FPTemplate
{
  ....
  FPTemplate operator<<(int numBits) const { return value << numBits; }
  FPTemplate operator>>(int numBits) const { return value << numBits; }

  FPTemplate& operator<<=(int numBits) { value <<= numBits; return *this;}
  FPTemplate& operator>>=(int numBits) { value >>= numBits; return *this;}
  ....
}

При перегрузке операторов сдвига программист допустил опечатку в одном из них, перепутав операторы << и >>. Скорее всего, это результат Copy-Paste-программирования.

Предупреждение 2

V557 Array overrun is possible. The value of 'nFormatLength' index could reach 16. EASprintfOrdered.cpp 246

static const int kSpanFormatCapacity = 16;

struct Span8
{
  ....
  char mFormat[kSpanFormatCapacity];
  ....
};

static int OVprintfCore(....)
{
  ....
  EA_ASSERT(nFormatLength < kSpanFormatCapacity);
  if(nFormatLength < kSpanFormatCapacity)
    spans[spanIndex].mFormat[nFormatLength++] = *p;                        // <=
  else
    return -1;

  switch(*p)
  {
    case 'b': case 'd': case 'i': case 'u': case 'o': case 'x': case 'X':
    case 'g': case 'G': case 'e': case 'E': case 'f': case 'F': case 'a':
    case 'A': case 'p': case 'c': case 'C': case 's': case 'S': case 'n':
    {
      // Finalize the current span.
      spans[spanIndex].mpEnd = p + 1;
      spans[spanIndex].mFormat[nFormatLength] = 0;                         // <=
      spans[spanIndex].mFormatChar = *p;
      if(++spanIndex == kSpanCapacity)
        break;
  ....
}

Массив spans[spanIndex].mFormat состоит из 16 элементов, т.е. последний валидный элемент имеет индекс 15. Сейчас код функции OVprintfCore написан так, что если индекс nFormatLength будет иметь максимально возможный индекс - 15, то произойдёт инкремент до 16. Далее в операторе switch возможен выход за границу массива.

Этот фрагмент кода скопирован ещё в 2 места:

  • V557 Array overrun is possible. The value of 'nFormatLength' index could reach 16. EASprintfOrdered.cpp 614
  • V557 Array overrun is possible. The value of 'nFormatLength' index could reach 16. EASprintfOrdered.cpp 977

Предупреждение 3

V560 A part of conditional expression is always true: (result >= 0). EASprintfOrdered.cpp 489

static int OVprintfCore(....)
{
  ....
  for(result = 1; (result >= 0) && (p < pEnd); ++p)
  {
    if(pWriteFunction8(p, 1, pWriteFunctionContext8, kWFSIntermediate) < 0)
      return -1;
    nWriteCountSum += result;
  }
  ....
}

Условие result >= 0 всегда истинно, потому что переменная result нигде в цикле не меняется. Код выглядит очень подозрительно и, скорее всего, имеет место ошибка в этом коде.

Этот фрагмент кода скопирован ещё в 2 места:

  • V560 A part of conditional expression is always true: (result >= 0). EASprintfOrdered.cpp 852
  • V560 A part of conditional expression is always true: (result >= 0). EASprintfOrdered.cpp 1215

Предупреждение 4

V1009 Check the array initialization. Only the first element is initialized explicitly. The rest elements are initialized with zeros. EASprintfOrdered.cpp 151

static int OVprintfCore(....)
{
  ....
  int spanArgOrder[kArgCapacity] = { -1 };
  ....
}

Возможно, это не является ошибкой, но разработчиков следует предупредить, что значением -1 инициализируется только первый элемент массива spanArgOrder, а все остальные будут иметь значение 0.

Этот фрагмент кода скопирован ещё в 2 места:

  • V1009 Check the array initialization. Only the first element is initialized explicitly. The rest elements are initialized with zeros. EASprintfOrdered.cpp 518
  • V1009 Check the array initialization. Only the first element is initialized explicitly. The rest elements are initialized with zeros. EASprintfOrdered.cpp 881

Предупреждение 5

V728 An excessive check can be simplified. The '(A && !B) || (!A && B)' expression is equivalent to the 'bool(A) != bool(B)' expression. int128.h 1242

inline void int128_t::Modulus(....) const
{
  ....
  bool bDividendNegative = false;
  bool bDivisorNegative = false;
  ....
  if(    (bDividendNegative && !bDivisorNegative)
     || (!bDividendNegative &&  bDivisorNegative))
  {
    quotient.Negate();
  }
  ....
}

Этот фрагмент кода был отформатирован для удобства, но в оригинале это очень длинное условие, которое сложно читать. Другое дело, если мы упростим условное выражение, как советует анализатор:

if( bDividendNegative != bDivisorNegative)
{
  quotient.Negate();
}

Код стал значительно короче, что сильно упростило понимание логики условного выражения.

Заключение

Как вы могли заметить, большинство подозрительных предупреждений продублированы в трех местах, причём в пределах одного и того же файла. Дублирование кода является очень плохой практикой разработки, т.к. усложняет поддержку кода. А если в такой код попадает ошибка, то стабильность программы резко снижается из-за распространения ошибок по всему коду.

Будем надеется, что опубликуют ещё что-то интересное и мы вновь вернёмся в этот репозиторий :). Ну а пока предлагаю желающим скачать PVS-Studio и попробовать проверить собственные проекты.

Популярные статьи по теме
64-битные ошибки: LONG, LONG_PTR и привет из прошлого

Дата: 09 Мар 2023

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

В целом, 64-битные ошибки - дело минувших дней. Мало кто сейчас занимается портированием кода с 32-битной на 64-битную систему. Кому это было нужно, уже портировали свои приложения. Кому не нужно, то…
Приключения капитана Блада: потонет ли Арабелла?

Дата: 14 Фев 2023

Автор: Владислав Столяров

Недавно в сети появилась новость о том, что был открыт исходный код игры "Приключения капитана Блада". Мы не смогли пройти мимо и проверили его качество с помощью PVS-Studio. Потонет ли легендарный к…
Тонкости C++: итак, вы объявили класс…

Дата: 07 Фев 2023

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

Во время работы наша команда постоянно сталкивается с некоторыми особенностями языка, которые могут быть неизвестны рядовому C++ программисту. В этой статье мы расскажем о том, как работает, казалось…
Под капотом SAST: как инструменты анализа кода ищут дефекты безопасности

Дата: 26 Янв 2023

Автор: Сергей Васильев

Сегодня речь о том, как SAST-решения ищут дефекты безопасности. Расскажу, как разные подходы к поиску потенциальных уязвимостей дополняют друг друга, зачем нужен каждый из них и как теория ложится на…
Ложные представления программистов о неопределённом поведении

Дата: 17 Янв 2023

Автор: Гость

Неопределённое поведение (UB) – непростая концепция в языках программирования и компиляторах. Я слышал много заблуждений в том, что гарантирует компилятор при наличии UB. Это печально, но неудивитель…

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

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