﻿# Дефекты безопасности, которые устранила команда PVS\-Studio на этой неделе: выпуск N4

Мы решили в меру своих сил регулярно искать и устранять потенциальные уязвимости и баги в различных проектах\. Можно назвать это помощью open\-source проектам\. Можно \- разновидностью рекламы или тестированием анализатора\. Еще вариант \- очередной способ привлечения внимания к вопросам качества и надёжности кода\. На самом деле, не важно название, просто нам нравится это делать\. Назовём это необычным хобби\. Давайте посмотрим, что интересного было обнаружено в коде различных проектов на этой неделе\. Мы нашли время сделать исправления и предлагаем вам ознакомиться с ними\.

![0494_vulnerabilities_N4_ru/image1.png](https://import.viva64.com/docx/blog/0494_vulnerabilities_N4_ru/image1.png)

## Для тех, кто ещё не знаком с инструментом PVS\-Studio

[PVS\-Studio](https://pvs-studio.ru/ru/pvs-studio/) — это инструмент, который выявляет в коде многие разновидности ошибок и уязвимостей\. PVS\-Studio выполняет статический анализ кода и рекомендует программисту обратить внимание на участки программы, в которых с большой вероятностью содержатся ошибки\. Наилучший эффект достигается тогда, когда статический анализ выполняется регулярно\. Идеологически предупреждения анализатора подобны предупреждениям компилятора\. Но в отличии от компиляторов, PVS\-Studio выполняет более глубокий и разносторонний анализ кода\. Это позволяет ему находить ошибки в том числе и в компиляторах: [GCC](https://pvs-studio.ru/ru/blog/posts/cpp/0425/); LLVM [1](https://pvs-studio.ru/ru/blog/posts/0108/), [2](https://pvs-studio.ru/ru/blog/posts/cpp/0155/), [3](https://pvs-studio.ru/ru/blog/posts/cpp/0446/); [Roslyn](https://pvs-studio.ru/ru/blog/posts/csharp/0363/)\.

Поддерживается анализ кода на языках C, C\+\+ и C\#\. Анализатор работает под управлением Windows и Linux\. В Windows анализатор может интегрироваться как плагин в Visual Studio\.

Для дальнейшего знакомства с анализатором, предлагаем изучить следующие материалы:

* В формате [видео](https://www.youtube.com/watch?v=kmqF130pQW8&feature=youtu.be) презентация доступна на YouTube \(47 минут\)\. 
* [Статьи](https://pvs-studio.ru/ru/blog/inspections/) о проверенных открытых проектах\.
* [PVS\-Studio: поиск дефектов безопасности](https://pvs-studio.ru/ru/blog/posts/cpp/0486/)\.

## Потенциальные уязвимости \(weaknesses\)

В этом разделе приведены дефекты, которые попадают под классификацию CWE и, по сути, являются потенциальными уязвимостями\. Конечно, не в каждом проекте дефекты безопасности создают какую\-то практическую угрозу, но хочется продемонстрировать, что мы умеем находить подобные ситуации\.

**1\. CryEngine V\. CWE\-806 \(Buffer Access Using Size of Source Buffer\)**

[V512](https://pvs-studio.ru/ru/docs/warnings/v512/) A call of the 'memcpy' function will lead to underflow of the buffer 'hashableData'\. GeomCacheRenderNode\.cpp 285

```cpp
void CGeomCacheRenderNode::Render(....)
{
  ....
  CREGeomCache* pCREGeomCache = iter->second.m_pRenderElement;
  ....
  uint8 hashableData[] =
  {
   0, 0, 0, 0, 0, 0, 0, 0,
   (uint8)std::distance(pCREGeomCache->....->begin(), &meshData),
   (uint8)std::distance(meshData....->....begin(), &chunk),
   (uint8)std::distance(meshData.m_instances.begin(), &instance)
  };

  memcpy(hashableData,pCREGeomCache,sizeof(pCREGeomCache)); // <=
  ....
}
```

**2\. CryEngine V\. CWE\-467 \(Use of sizeof\(\) on a Pointer Type\)**

[V568](https://pvs-studio.ru/ru/docs/warnings/v568/) It's odd that 'sizeof\(\)' operator evaluates the size of a pointer to a class, but not the size of the 'this' class object\. ClipVolumeManager\.cpp 145

```cpp
void
CClipVolumeManager::GetMemoryUsage(class ICrySizer* pSizer) const
{
  pSizer->AddObject(this, sizeof(this));
  for (size_t i = 0; i < m_ClipVolumes.size(); ++i)
    pSizer->AddObject(m_ClipVolumes[i].m_pVolume);
}
```

**3\. CryEngine V\. CWE\-571 \(Expression is Always True\)**

[V501](https://pvs-studio.ru/ru/docs/warnings/v501/) There are identical sub\-expressions to the left and to the right of the '\=\=' operator: bActive \=\= bActive LightEntity\.h 124

```cpp
void SetActive(bool bActive)
{
  if (bActive == bActive)
    return;

  m_bActive = bActive;
  OnResetState();
}
```

**4\. CryEngine V\. CWE\-476 \(NULL Pointer Dereference\)**

[V595](https://pvs-studio.ru/ru/docs/warnings/v595/) The 'pTrack' pointer was utilized before it was verified against nullptr\. Check lines: 60, 61\. AudioNode\.cpp 60

```cpp
void CAudioNode::Animate(SAnimContext& animContext)
{
  ....
  const bool bMuted = gEnv->IsEditor() && (pTrack->GetFlags() &
    IAnimTrack::eAnimTrackFlags_Muted);
  if (!pTrack || pTrack->GetNumKeys() == 0 ||
       pTrack->GetFlags() & IAnimTrack::eAnimTrackFlags_Disabled)
  {
    continue;
  }
  ....
}
```

**5\. CryEngine V\. CWE\-688 \(Function Call With Incorrect Variable or Reference as Argument\)**

[V549](https://pvs-studio.ru/ru/docs/warnings/v549/) The first argument of 'memcpy' function is equal to the second argument\. ObjectsTree\_Serialize\.cpp 1135

```cpp
void COctreeNode::LoadSingleObject(....)
{
  ....
  float* pAuxDataDst = pObj->GetAuxSerializationDataPtr(....);
  const float* pAuxDataSrc = StepData<float>(....);
  memcpy(pAuxDataDst, pAuxDataDst, min(....) * sizeof(float));
  ....
}
```

**6\. LLVM\. CWE\-476 \(NULL Pointer Dereference\)**

[V595](https://pvs-studio.ru/ru/docs/warnings/v595/) The 'DIExpr' pointer was utilized before it was verified against nullptr\. Check lines: 949, 950\. codeviewdebug\.cpp 949

```cpp
void CodeViewDebug::collectVariableInfo(const DISubprogram *SP) {
  ....
  const DIExpression *DIExpr = DVInst->getDebugExpression();
  bool IsSubfield = false;
  unsigned StructOffset = 0;

  // Handle fragments.
  auto Fragment = DIExpr->getFragmentInfo();   // <=
  if (DIExpr && Fragment) {                    // <=
    IsSubfield = true;
    StructOffset = Fragment->OffsetInBits / 8;
  } else if (DIExpr && DIExpr->getNumElements() > 0) {
    continue; // Ignore unrecognized exprs.
  }
  ....
}
```

Bug Report: [https://bugs\.llvm\.org/show\_bug\.cgi?id\=32430](https://bugs.llvm.org/show_bug.cgi?id=32430)

**7\. LLVM\. CWE\-476 \(NULL Pointer Dereference\)**

[V595](https://pvs-studio.ru/ru/docs/warnings/v595/) The 'Initializer' pointer was utilized before it was verified against nullptr\. Check lines: 335, 338\. semaoverload\.cpp 335

```cpp
NarrowingKind
StandardConversionSequence::getNarrowingKind(....) const {
  ....
  const Expr *Initializer = IgnoreNarrowingConversion(Converted);

  if (Initializer->isValueDependent()) // <=
    return NK_Dependent_Narrowing;

  if (Initializer &&                   // <=
      Initializer->isIntegerConstantExpr(IntConstantValue, Ctx)){
  ....
}
```

Bug Report: [https://bugs\.llvm\.org/show\_bug\.cgi?id\=32447](https://bugs.llvm.org/show_bug.cgi?id=32447)

**8\. RPCS3\. CWE\-570 \(Expression is Always False\)**

[V547](https://pvs-studio.ru/ru/docs/warnings/v547/) Expression 'sock < 0' is always false\. Unsigned type value is never < 0\. sys\_net\.cpp 695

```cpp
#ifdef _WIN32
  using socket_t = SOCKET;
#else
  using socket_t = int;
#endif
s32 socket(s32 family, s32 type, s32 protocol)
{
  ....
  socket_t sock = ::socket(family, type, protocol);

  if (sock < 0)
  {
    libnet.error("socket()....", get_errno() = get_last_error());
    return -1;
  }
  ....
}
```

Pull Request: [https://github\.com/RPCS3/rpcs3/pull/2543](https://github.com/RPCS3/rpcs3/pull/2543)

## Прочие ошибки

**1\. CoreCLR**

[V778](https://pvs-studio.ru/ru/docs/warnings/v778/) Two similar code fragments were found\. Perhaps, this is a typo and 'IMAGE\_LOADED\_FOR\_INTROSPECTION' variable should be used instead of 'IMAGE\_LOADED'\. cee\_dac peimage\.cpp 811

```cpp
void PEImage::EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
{
  ....
  if (m_pLayouts[IMAGE_LOADED].IsValid() &&
      m_pLayouts[IMAGE_LOADED]!=NULL)
    m_pLayouts[IMAGE_LOADED]->EnumMemoryRegions(flags);

  if (m_pLayouts[IMAGE_LOADED_FOR_INTROSPECTION].IsValid() &&
      m_pLayouts[IMAGE_LOADED]!=NULL)                   // <=
    m_pLayouts[IMAGE_LOADED_FOR_INTROSPECTION]->
      EnumMemoryRegions(flags);
}
```

Pull Request: [https://github\.com/dotnet/coreclr/pull/10450](https://github.com/dotnet/coreclr/pull/10450)

**2\. CoreCLR**

[V778](https://pvs-studio.ru/ru/docs/warnings/v778/) Two similar code fragments were found\. Perhaps, this is a typo and 'weight2' variable should be used instead of 'weight1'\. clrjit lclvars\.cpp 2702

```cpp
int __cdecl Compiler::RefCntCmp(const void* op1, const void* op2)
{
  ....
  if (weight1)
  {
    ....
    if (varTypeIsGC(dsc1->TypeGet()))
    {
      weight1 += BB_UNITY_WEIGHT / 2;
    }
    if (dsc1->lvRegister)
    {
      weight1 += BB_UNITY_WEIGHT / 2;
    }
  }

  if (weight1)
  {
    ....
    if (varTypeIsGC(dsc2->TypeGet()))
    {
      weight1 += BB_UNITY_WEIGHT / 2;  // <=
    }
    if (dsc2->lvRegister)
    {
      weight2 += BB_UNITY_WEIGHT / 2;
    }
  }
  ....
}
```

Pull Request: [https://github\.com/dotnet/coreclr/pull/10450](https://github.com/dotnet/coreclr/pull/10450)

**3\. CoreCLR**

[V778](https://pvs-studio.ru/ru/docs/warnings/v778/) Two similar code fragments were found\. Perhaps, this is a typo and 'g\_szBuf\_ProperName' variable should be used instead of 'g\_szBuf\_UnquotedProperName'\. ildasm dasm\.cpp 486

```cpp
void Uninit()
{
  ....
  if (g_szBuf_UnquotedProperName != NULL)
  {
    SDELETE(g_szBuf_UnquotedProperName);
  }
  if (g_szBuf_UnquotedProperName != NULL)  // <=
  {
    SDELETE(g_szBuf_ProperName);
  }
  ....
}
```

Pull Request: [https://github\.com/dotnet/coreclr/pull/10450](https://github.com/dotnet/coreclr/pull/10450)

**4\. LLVM**

[V778](https://pvs-studio.ru/ru/docs/warnings/v778/) Two similar code fragments were found\. Perhaps, this is a typo and 'FS' variable should be used instead of 'TS'\. hexagonearlyifconv\.cpp 549

```cpp
bool HexagonEarlyIfConversion::isProfitable(....) const
{
  ....
  unsigned TS = 0, FS = 0, Spare = 0;
  if (FP.TrueB) {
    TS = std::distance(FP.TrueB->begin(),
      FP.TrueB->getFirstTerminator());
    if (TS < HEXAGON_PACKET_SIZE)
      Spare += HEXAGON_PACKET_SIZE-TS;     // <=
  }
  if (FP.FalseB) {
    FS = std::distance(FP.FalseB->begin(),
      FP.FalseB->getFirstTerminator());
    if (FS < HEXAGON_PACKET_SIZE)
      Spare += HEXAGON_PACKET_SIZE-TS;     // <=
  }
  unsigned TotalIn = TS+FS;
  ....
}
```

Bug Report: [https://bugs\.llvm\.org/show\_bug\.cgi?id\=32480](https://bugs.llvm.org/show_bug.cgi?id=32480)

## Заключение

Предлагаем скачать анализатор PVS\-Studio и попробовать проверить ваш проект:

* Скачать [PVS\-Studio для Windows](https://pvs-studio.ru/ru/pvs-studio/download/)
* Скачать [PVS\-Studio для Linux](https://pvs-studio.ru/ru/pvs-studio/download/)

Для снятия [ограничения](https://pvs-studio.ru/ru/docs/manual/0009/) демонстрационной версии, вы можете [написать](https://pvs-studio.ru/ru/about-feedback/) нам, и мы отправим вам временный ключ\.

Для быстрого знакомства с анализатором, вы можете воспользоваться утилитами, отслеживающими запуски компилятора и собирающие для проверки всю необходимую информацию\. См\. описание утилиты [CLMonitoring](https://pvs-studio.ru/ru/docs/manual/0031/) и [pvs\-studio\-analyzer](https://pvs-studio.ru/ru/docs/manual/0036/)\. Если вы работаете с классическим типом проекта в Visual Studio, то всё ещё проще: достаточно выбрать в меню PVS\-Studio команду "Check Solution"\.