﻿# Анализ проекта TrinityCore с помощью PVS\-Studio

TrinityCore \- бесплатный проект, распространяемый под лицензией GPL\. Целью проекта является создание альтернативного программного обеспечения для эмулирования сервера многопользовательской игры World of Warcraft от Blizzard Entertainment\. Основная цель проекта –  обучающая\. Проект ни в коем случаи не направлен на извлечение прибыли от использования\. Исходный код, который написан на C и C\+\+, является открытым, это значит, что он распространяется свободно, при этом на пользователя не накладывается никаких обязательств\.  

Мы проверили проект, используя анализатор [PVS\-Studio](https://pvs-studio.ru/ru/pvs-studio/) версии 4\.54\. Ошибок найдено немного и в основном они относятся к внешним библиотекам\. Чтобы подробно проанализировать проект можно воспользоваться триальной версией PVS\-Studio\. Её будет [достаточно](https://pvs-studio.ru/ru/docs/manual/0009/), чтобы просмотреть все подозрительные участки кода\. Здесь перечислим только некоторые фрагменты кода, на которых остановился взгляд:

**1\. Опечатка\. Два раза используется 'other\.y'\.**

```cpp
inline Vector3int32& operator+=(const Vector3int32& other)
{
  x += other.x;
  y += other.y;
  z += other.y;
  return *this;
}
```

PVS\-Studio: V537 Consider reviewing the correctness of 'y' item's usage\. g3dlib vector3int32\.h 77

**2\. Ошибка в макросе NEXT\_CMP\_VALUE\.**

```cpp
static struct wordvalue doubles[] = {
 { "ch", (uchar*) "\014\031\057\057" },
 { "Ch", (uchar*) "\014\031\060\060" },
 { "CH", (uchar*) "\014\031\061\061" },
 { "c",  (uchar*) "\005\012\021\021" },
 { "C",  (uchar*) "\005\012\022\022" },
 };

#define NEXT_CMP_VALUE(src, p, store, pass, value, len) \
while (1)                                      \
{                                              \
  ......                                       \
  for (i = 0; i < (int) sizeof(doubles); i++)  \
  {                                            \
    const char * pattern = doubles[i].word;    \
    ...                                        \
    }                                          \
  }                                            \
  ......                                       \
}
```

PVS\-Studio: V557 Array overrun is possible\. The value of 'i' index could reach 39\. libmysql ctype\-czech\.c 260

Корректный код должен выглядеть так:

```cpp
for (i = 0; i < (int) sizeof(doubles) / sizeof(doubles[0]); i++)
```

**3\. Копирование только части строки\.**

```cpp
class ACE_Name_Request
{
  ...
  char *type_;
};

void
ACE_Name_Request::type (const char *c)
{
  ACE_TRACE ("ACE_Name_Request::type");
  ACE_OS::strsncpy (this->type_,
                    c,
                    sizeof this->type_);
}
```

PVS\-Studio: V579 The strsncpy function receives the pointer and its size as arguments\. It is possibly a mistake\. Inspect the third argument\. ace name\_request\_reply\.cpp 251

Вместо длины строки вычисляется размер указателя\.

**4\. Недоочищенный буфер\.**

```cpp
ACE_INLINE int
ACE_Thread::disablecancel(struct cancel_state *old_state)
{
  ...
  ACE_OS::memset (old_state,
                  0,
                  sizeof (old_state));
  ...
}
```

PVS\-Studio: V579 The memset function receives the pointer and its size as arguments\. It is possibly a mistake\. Inspect the third argument\. ace thread\.inl 172

**5\. Ошибка при cравнении матриц\.**

```cpp
bool Matrix4::operator==(const Matrix4& other) const {
  if (memcmp(this, &other, sizeof(Matrix4) == 0)) {
    return true;
  } 
  ...
}
```

PVS\-Studio: V575 The 'memcmp' function processes '0' elements\. Inspect the third argument\. g3dlib matrix4\.cpp 385

**6\. Всегда истинное условие\.**

```cpp
enum enum_mysql_timestamp_type
str_to_datetime(....)
{
  ...
  else if (str[0] != 'a' || str[0] != 'A')
  ...
}
```

PVS\-Studio: V547 Expression 'str\[0\] \!\= 'a' \|\| str\[0\] \!\= 'A'' is always true\. Probably the '&&' operator should be used here\. libmysql my\_time\.c 340

**7\. Не там поставленная скобка\.**

```cpp
static my_bool socket_poll_read(my_socket sd, uint timeout)
{
  int res;
  ...
  if ((res = select((int) fd,
         &readfds, NULL, &errorfds, &tm) <= 0))
  {
    DBUG_RETURN(res < 0 ? 0 : 1);
  }
  ...
}
```

PVS\-Studio: V593 Consider reviewing the expression of the 'A \= B <\= C' kind\. The expression is calculated as following: 'A \= \(B <\= C\)'\. libmysql viosocket\.c 550

Корректный код должен выглядеть так:

```cpp
if ((res= select((int) fd,
            &readfds, NULL, &errorfds, &tm)) <= 0)
```

**8\. Неправильные проверки указатель на значение 0\.**

Достаточно много обнаруживается проверок, что указатель равен 0, уже после того, как указатель использовали\. Первый пример:

```cpp
bool OnCheck(Player* player, Unit* /*target*/)
{
  bool checkArea =
    player->GetAreaId() == AREA_ARGENT_TOURNAMENT_FIELDS ||
    player->GetAreaId() == AREA_RING_OF_ASPIRANTS ||
    player->GetAreaId() == AREA_RING_OF_ARGENT_VALIANTS ||
    player->GetAreaId() == AREA_RING_OF_ALLIANCE_VALIANTS ||
    player->GetAreaId() == AREA_RING_OF_HORDE_VALIANTS ||
    player->GetAreaId() == AREA_RING_OF_CHAMPIONS;

  return player && checkArea &&
         player->duel && player->duel->isMounted;
}
```

PVS\-Studio: V595 The 'player' pointer was utilized before it was verified against nullptr\. Check lines: 310, 312\. scripts achievement\_scripts\.cpp 310

Еще один пример:

```cpp
CreatureAI* GetAI(Creature* creature) const
{
  ...
  Item* item =
    player->StoreNewItem(dest, ITEM_TEAR_OF_GODDESS, true);
  if (item && player)
    player->SendNewItem(item, 1, true, false, true);
  ...
}
```

PVS\-Studio: V595 The 'player' pointer was utilized before it was verified against nullptr\. Check lines: 224, 225\. scripts hyjal\.cpp 224

**Вывод**

С трудом верится, что этот проект разрабатывается энтузиастами, обучающимися программированию\. Здесь перечислены не все замеченные недостатки\. Но всё равно найденных ошибок слишком мало\. Возможно, кто\-то из разработчиков уже использовал PVS\-Studio для проверки TrinityCore\. Косвенным подтверждением является то, что больше всего ошибок находится с помощью диагностического правила V595\. А эта диагностика появилась совсем недавно\.