﻿# В ожидании Linux версии: проверка кода графического редактора Inkscape

В этой статье речь пойдет о проверке еще одного известного open source проекта \- векторного графического редактора Inkscape 0\.92\. Проект развивается уже более 12 лет и предоставляет множество возможностей по работе с различными форматами векторных иллюстраций\. За это время его кодовая база выросла до 600 тысяч строк, и пришло время проверить его с помощью статического анализатора PVS\-Studio\.

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



## Введение

Inkscape \- это кроссплатформенный свободный векторный графический редактор\. Он широко используется любителями и профессионалами по всему миру для создания иллюстраций, иконок, логотипов, диаграмм, карт, а также веб\-графики\. Inkscape стал одним из самых популярных редакторов в своей области\. Проект был создан в 2003 году как форк проекта Sodipodi, и до сих пор продолжает развиваться\. Подробнее про Inkscape можно прочитать на [официальном сайте](https://inkscape.org/)\.

Для проверки использовалась последняя версия Inkscape \- 0\.92, код которой доступен в [репозитории на GitHub](https://github.com/inkscape/inkscape), и статический анализатор PVS\-Studio 6\.07, загрузить который можно по [ссылке](https://pvs-studio.ru/ru/pvs-studio/download/)\. Правда, на момент написания статьи для скачивания доступна только PVS\-Studio для Windows\. Но ситуация скоро изменится\. И можно уже заранее записаться в добровольцы для тестирования бета\-версии PVS\-Studio для Linux\. Подробности можно узнать из статьи: "[PVS\-Studio признаётся в любви к Linux](https://pvs-studio.ru/ru/blog/posts/0415/)"\.

![0419_Inkscape_ru/image2.png](https://import.viva64.com/docx/blog/0419_Inkscape_ru/image2.png)

Но вернемся к ошибкам\. Хочу отметить, что в статье были выбраны и описаны наиболее интересные сообщения анализатора\. Для более тщательной проверки авторы проекта смогут получить у нас временный ключ для PVS\-Studio и отчёт\. Так как публичной PVS\-Studio пока нет, для просмотра отчёта они смогут воспользоваться инструментом PVS\-Studio Standalone, работающим под Windows\. Да, это не удобно\. Но прошу всех потерпеть, осталось не так долго до счастливого момента выхода PVS\-Studio для Linux\.

## Результаты проверки

## Проверка указателя на null после new

**Предупреждение PVS\-Studio:** [V668](https://pvs-studio.ru/ru/docs/warnings/v668/) There is no sense in testing the 'outputBuf' pointer against null, as the memory was allocated using the 'new' operator\. The exception will be generated in the case of memory allocation error\. gzipstream\.cpp 180

```cpp
bool GzipInputStream::load()
{
  ....
  outputBuf = new unsigned char [OUT_SIZE];
  if ( !outputBuf ) {  // <=
    delete[] srcBuf;
    srcBuf = NULL;
    return false;
  }
  ....
}
```

Согласно современному стандарту C\+\+, при невозможности выделить память оператор _new_ генерирует исключение _std::bad\_alloc\(\)_, а не возвращает _nullptr_\. В случае, если системе не удастся выделить память, будет выброшено исключение и выполнение функции прекратится, следовательно, программа никогда не зайдет в блок после условия\.

В данном случае это может привести к утечке памяти\. Самым очевидным решением проблемы является использование блока _try \{\.\.\.\.\} catch\(const std::bad\_alloc &\) \{\.\.\.\.\}_, но гораздо лучше вместо явного освобождения памяти использовать умные указатели \([smart pointers](https://en.wikipedia.org/wiki/smart_pointer)\)\.

Аналогичные проверки указателей:

* V668 There is no sense in testing the 'destbuf' pointer against null, as the memory was allocated using the 'new' operator\. The exception will be generated in the case of memory allocation error\. gzipstream\.cpp 397
* V668 There is no sense in testing the 'srcBuf' pointer against null, as the memory was allocated using the 'new' operator\. The exception will be generated in the case of memory allocation error\. gzipstream\.cpp 175
* V668 There is no sense in testing the 'oldcurve' pointer against null, as the memory was allocated using the 'new' operator\. The exception will be generated in the case of memory allocation error\. sp\-lpe\-item\.cpp 719

## Сравнение this с нулем

**Предупреждение PVS\-Studio:** [V704](https://pvs-studio.ru/ru/docs/warnings/v704/) '\!this' expression in conditional statements should be avoided \- this expression is always false on newer compilers, because 'this' pointer can never be NULL\. sp\-lpe\-item\.cpp 213

```cpp
bool SPLPEItem::performPathEffect(....) {
  if (!this) {
    return false;
  }
  ....
}
```

Согласно современному стандарту С\+\+, указатель _this_ никогда не может быть нулевым\. Зачастую использование сравнения _this_ с нулем может приводить к неожиданным ошибкам\.  Подробнее прочитать об этом можно в описании диагностики [V704](https://pvs-studio.ru/ru/docs/warnings/v704/)\.

Ещё одна проверка на равенство _this_ значению _nullptr_:

* V704 'this' expression in conditional statements should be avoided \- this expression is always true on newer compilers, because 'this' pointer can never be NULL\. sp\-paint\-server\.cpp 42

## Опасное переопределение параметра

**Предупреждение PVS\-Studio:** [V581](https://pvs-studio.ru/ru/docs/warnings/v581/) The conditional expressions of the 'if' operators situated alongside each other are identical\. Check lines: 1046, 1051\. sp\-mesh\-array\.cpp 1051

```cpp
void SPMeshNodeArray::create( ...., Geom::OptRect bbox ) // <=
{
  ....
  if( !bbox ) {
    std::cout << "SPMeshNodeArray::create(): bbox empty" 
              << std::endl;
    Geom::OptRect bbox = item->geometricBounds();        // <=
  }
  if( !bbox ) {                                          // <=
    std::cout << "ERROR: No bounding box!" 
              << std::endl;
    return;
  }
  ....
}
```

По задумке автора, в случае, когда параметр _bbox_ равен _nullptr_, для него должен создаться новый объект типа _Geom::OptRect_, и если объект создать не удалось, то происходит выход из метода с сообщением об ошибке\.

Однако, код работает совсем не так, как ожидал автор\. Когда параметр _bbox_ равен _nullptr_, внутри первого блока _if_ происходит создание совершенно нового объекта _bbox_, который сразу же уничтожается при выходе из этого блока\. В результате получается, что второе условие выполняется всегда, когда выполняется и первое, поэтому каждый раз, когда параметр _bbox_ равен _nullptr_, происходит выход из метода с сообщением об ошибке\.

Данный код следовало бы написать так:

```cpp
void SPMeshNodeArray::create( ...., Geom::OptRect bbox )
{
  ....
  if( !bbox ) {
    std::cout << "SPMeshNodeArray::create(): bbox empty" 
              << std::endl;
    bbox = item->geometricBounds();
    if( !bbox ) {
      std::cout << "ERROR: No bounding box!" 
                << std::endl;
      return;
    }
  }
  ....
}
```

## Неправильно закомментированная строка

**Предупреждение PVS\-Studio:** [V628](https://pvs-studio.ru/ru/docs/warnings/v628/) It's possible that the line was commented out improperly, thus altering the program's operation logics\. FontFactory\.cpp 705

```cpp
font_instance *font_factory::Face(....)
{
  ....
  if( features[0] != 0 ) // <=
    // std::cout << "          features: " << std::endl;

  for( unsigned k = 0; features[k] != 0; ++k ) {
  // dump_tag( &features[k], "            feature: ");
  ++(res->openTypeTables[ extract_tag(&features[k])]);
  }
  ....
}
```

Здесь автор забыл закомментировать строку с условием, которая использовалась для отладки\. В данном случае повезло и это не привело к негативным последствиям\. Получилось, что условие в _if_ просто продублировало условие выполнения цикла _for_ на первой итерации, но это несомненно является ошибкой и может привести к проблемам в будущем\.

## "Одноразовый цикл"

**Предупреждение PVS\-Studio:** [V612](https://pvs-studio.ru/ru/docs/warnings/v612/) An unconditional 'break' within a loop\. text\_reassemble\.c 417



```cpp
int TR_kern_gap(....)
{ 
  ....
  while(ptsp && tsp){
    ....
    if(!text32){
      ....
      if(!text32)break;
    }
    ....
    if(!ptxt32){
      ....
      if(!ptxt32)break;
    }
    ....
    break; // <=
  }
  ....
  return(kern);
}
```

Этот цикл в любом случае завершится после первого прохода, поскольку перед оператором _break_ нет никакого условия\. Точно сказать что подразумевал автор сложно\. Если ошибки здесь нет, то код всё равно лучше переписать и заменить _while_ на _if_\. 

## Очень странный метод

**Предупреждение PVS\-Studio:** [V571](https://pvs-studio.ru/ru/docs/warnings/v571/) Recurring check\. The 'back \=\= false' condition was already verified in line 388\. Path\.cpp 389

```cpp
void
Path::SetBackData (bool nVal)
{
  if (back == false) {
    if (nVal == true && back == false) {
      back = true;
      ResetPoints();
    } else if (nVal == false && back == true) {
      back = false;
      ResetPoints();
    }
  } else {
    if (nVal == true && back == false) {
      back = true;
      ResetPoints();
    } else if (nVal == false && back == true) {
      back = false;
      ResetPoints();
    }
  }
}
```

Сложно сказать, почему данный метод был написан столь странным образом\. Блоки _if_ и _else_ совпадают, производится множество лишних проверок\. Если даже логической ошибки здесь нет, то данный метод определенно следует переписать так:

```cpp
void
Path::SetBackData (bool nVal)
{
  back = nVal;
  ResetPoints();
}
```

## Потерянная запятая

**Предупреждение PVS\-Studio:** [V737](https://pvs-studio.ru/ru/docs/warnings/v737/) It is possible that ',' comma is missing at the end of the string\. drawing\-text\.cpp 272

```cpp
void DrawingText::decorateStyle(....)
{
  ....
  int dashes[16]={
     8,  7,   6,   5,
     4,  3,   2,   1,
    -8, -7,  -6,  -5  // <=
    -4, -3,  -2,  -1
  };
  ....
}
```

Была пропущена запятая, что приводит к тому, что массив _dashes_ будет проинициализирован совсем не такими значениями, которые ожидал автор\.

Ожидалось:

```cpp
{ 8,  7,  6,  5,
  4,  3,  2,  1,
 -8, -7, -6, -5,
 -4, -3, -2, -1 }
```

На самом деле массив будет заполнен так: 

```cpp
{ 8,  7,  6,  5, 
  4,  3,  2,  1,
 -8, -7, -6, -9,
 -3, -2, -1,  0 }
```

На место 12\-го элемента массива будет записано число _\-5 \- 4 \=\= \-9_\. А последний элемент \(на который не хватило элементов в списке инициализации массива\) будет, согласно стандарту C\+\+, инициализирован нулём\.

## Неверная длина в strncmp

**Предупреждение PVS\-Studio:** [V666](https://pvs-studio.ru/ru/docs/warnings/v666/) Consider inspecting third argument of the function 'strncmp'\. It is possible that the value does not correspond with the length of a string which was passed with the second argument\. blend\.cpp 85



```cpp
static Inkscape::Filters::FilterBlendMode
 sp_feBlend_readmode(....) {
  ....
  switch (value[0]) {
    case 'n':
      if (strncmp(value, "normal", 6) == 0)
        return Inkscape::Filters::BLEND_NORMAL;
      break;
    case 'm':
      ....
    case 's':
      if (strncmp(value, "screen", 6) == 0)
          return Inkscape::Filters::BLEND_SCREEN;
      if (strncmp(value, "saturation", 6) == 0) // <=
          return Inkscape::Filters::BLEND_SATURATION;
      break;
    case 'd':
      ....
    case 'o':
      if (strncmp(value, "overlay", 7) == 0)
          return Inkscape::Filters::BLEND_OVERLAY;
      break;
    case 'c':
      ....
    case 'h':
      if (strncmp(value, "hard-light", 7) == 0) // <=
          return Inkscape::Filters::BLEND_HARDLIGHT;
      ....
      break;
    ....
  }
}
```

В функцию _strncmp_ передается неверная длина строк _"saturation"_ и _"hard\-light",_ поэтому будут сравниваться не все символы, а только первые 6 и 7 символов соответственно\. Скорее всего, здесь проявило себя т\.н\. [Copy\-Paste программирование](https://pvs-studio.ru/ru/blog/terms/0068/)\. Эта ошибка приведет к ложным срабатываниям при добавлении новых элементов в _switch\-case_\. Стоило бы исправить код:

```cpp
if (strncmp(value, "saturation", 10) == 0)
....
if (strncmp(value, "hard-light", 10) == 0)
```

## Потенциальное деление на ноль

**Предупреждение PVS\-Studio:** [V609](https://pvs-studio.ru/ru/docs/warnings/v609/) Divide by zero\. Denominator range \[0\.\.999\]\. lpe\-fillet\-chamfer\.cpp 607

```cpp
Geom::PathVector
LPEFilletChamfer::doEffect_path(....)
{
  ....
  if(....){
    ....
  } else if (type >= 3000 && type < 4000) {
      unsigned int chamferSubs = type-3000;
      ....
      double chamfer_stepsTime = 1.0/chamferSubs;
      ....
  }
  ...
}
```

В случае, когда переменная _type_ будет равна _3000_, значение переменной _chamferSubs_ составит 0\. Соответственно, значение _chamfer\_stepsTime_ будет равно _1\.0/0 \=\= inf_, а это явно не то, чего ожидает автор\. Чтобы избежать подобной ситуации стоит изменить условие в блоке _if_:

```cpp
...
else if (type > 3000 && type < 4000)
...
```

Или же можно отдельно обрабатывать ситуацию, когда _chamferSubs \=\= 0_\.

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

* V609 Divide by zero\. Denominator range \[0\.\.999\]\. lpe\-fillet\-chamfer\.cpp 623

## Пропущенный else?

**Предупреждение PVS\-Studio:** [V646](https://pvs-studio.ru/ru/docs/warnings/v646/) Consider inspecting the application's logic\. It's possible that 'else' keyword is missing\. sp\-item\.cpp 204



```cpp
void SPItem::resetEvaluated() 
{
  if ( StatusCalculated == _evaluated_status ) {
    ....
  } if ( StatusSet == _evaluated_status ) { // <=
      ....
  }
}
```

Судя по форматированию кода \(оператор _if_ расположен на той же строке, что и закрывающаяся скобка от предыдущего _if_\) и логике работы, здесь было пропущено ключевое слово _else_:

```cpp
....
if ( StatusCalculated == _evaluated_status ) {
    ....
  } else if ( StatusSet == _evaluated_status ) {
      ....
  }
}
....
```

## Работа с нулевым указателем

**Предупреждение PVS\-Studio:** [V595](https://pvs-studio.ru/ru/docs/warnings/v595/) The 'priv' pointer was utilized before it was verified against nullptr\. Check lines: 154, 160\. document\.cpp 154

```cpp
SPDocument::~SPDocument() 
{
  priv->destroySignal.emit();                      // <=
  ....
  if (oldSignalsConnected) {
    priv->selChangeConnection.disconnect();        // <=
    priv->desktopActivatedConnection.disconnect(); // <=
  } else {
    ....
  }
  if (priv) {                                      // <=
    ....
  }
  ....
}
```

В нижнем блоке _if_ происходит проверка _priv_ на _NULL_, т\.к\. автор допускает равенство этого указателя нулю, однако, выше указатель уже используется и без всяких проверок\. Чтобы исправить эту ошибку следует проверить значение указателя до того, как его использовать\.

Аналогичные предупреждения:

* V595 The 'parts' pointer was utilized before it was verified against nullptr\. Check lines: 624, 641\. sp\-offset\.cpp 624
* V595 The '\_effects\_list' pointer was utilized before it was verified against nullptr\. Check lines: 103, 113\. effect\.cpp 103
* V595 The 'num' pointer was utilized before it was verified against nullptr\. Check lines: 1312, 1315\. cr\-tknzr\.c 1312
* V595 The 'selector' pointer was utilized before it was verified against nullptr\. Check lines: 3463, 3481\. cr\-parser\.c 3463
* V595 The 'a\_this' pointer was utilized before it was verified against nullptr\. Check lines: 1552, 1562\. cr\-sel\-eng\.c 1552
* V595 The 'FillData' pointer was utilized before it was verified against nullptr\. Check lines: 5898, 5901\. upmf\.c 5898
* V595 The 'event\_context' pointer was utilized before it was verified against nullptr\. Check lines: 1014, 1023\. tool\-base\.cpp 1014
* V595 The 'event\_context' pointer was utilized before it was verified against nullptr\. Check lines: 959, 970\. tool\-base\.cpp 959
* V595 The 'this\-\>repr' pointer was utilized before it was verified against nullptr\. Check lines: 662, 665\. eraser\-tool\.cpp 662
* V595 The 'this\-\>repr' pointer was utilized before it was verified against nullptr\. Check lines: 662, 665\. eraser\-tool\.cpp 662
* V595 The 'modified\_connection' pointer was utilized before it was verified against nullptr\. Check lines: 1114, 1122\. gradient\-vector\.cpp 1114
* V595 The 'c' pointer was utilized before it was verified against nullptr\. Check lines: 762, 770\. freehand\-base\.cpp 762
* V595 The 'release\_connection' pointer was utilized before it was verified against nullptr\. Check lines: 505, 511\. gradient\-toolbar\.cpp 505
* V595 The 'modified\_connection' pointer was utilized before it was verified against nullptr\. Check lines: 506, 514\. gradient\-toolbar\.cpp 506

## Пропущенная точка с запятой

**Предупреждение PVS\-Studio**: [V504](https://pvs-studio.ru/ru/docs/warnings/v504/) It is highly probable that the semicolon ';' is missing after 'return' keyword\. svg\-fonts\-dialog\.cpp 167

```cpp
void GlyphComboBox::update(SPFont* spfont)
{
  if (!spfont) return // <=
//TODO: figure out why do we need to append("")
// before clearing items properly...

//Gtk is refusing to clear the combobox 
//when I comment out this line
  this->append(""); 
  this->remove_all();
}
```

![0419_Inkscape_ru/image3.png](https://import.viva64.com/docx/blog/0419_Inkscape_ru/image3.png)

После _return_ пропущена точка с запятой \(";"\), что и является причиной проблемы, описанной в комментариях автора\. Поскольку, если закомментировать строку:

```cpp
 this->append("");
```

то получится конструкция вида:

```cpp
if (!spfont) return this->remove_all();
```

Соответственно, combobox будет очищаться только в случае, когда _spfont \=\= NULL_\.

## Неиспользуемый параметр

**Предупреждение PVS\-Studio:** [V763](https://pvs-studio.ru/ru/docs/warnings/v763/) Parameter 'new\_value' is always rewritten in function body before being used\. sp\-xmlview\-tree\.cpp 259

```cpp
void element_attr_changed(.... const gchar * new_value, ....)
{
  NodeData *data = static_cast<NodeData *>(ptr);
  gchar *label;

  if (data->tree->blocked) return;

  if (0 != strcmp (key, "id") &&
      0 != strcmp (key, "inkscape:label"))
        return;

  new_value = repr->attribute("id"); // <=
  ....
}
```

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

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

* V763 Parameter 'widget' is always rewritten in function body before being used\. ruler\.cpp 923

## Указатель на несуществующий массив

**Предупреждение PVS\-Studio:** [V507](https://pvs-studio.ru/ru/docs/warnings/v507/) Pointer to local array 'n' is stored outside the scope of this array\. Such a pointer will become invalid\. inkscape\.cpp 582

```cpp
void
Application::crash_handler (int /*signum*/)
{
  ....
  if (doc->isModifiedSinceSave()) {
    const gchar *docname;
  ....
  if (docname) {
    ....
    if (*d=='.' && d>docname && dots==2) {
      char n[64];
      size_t len = MIN (d - docname, 63);
      memcpy (n, docname, len);
      n[len] = '\0';
      docname = n;
    }
  }
  if (!docname || !*docname) docname = "emergency";
  ....
}
```

Массив _n_ имеет время жизни меньше, чем время жизни указателя _docname_ на него\. Это приводит к работе с недействительным указателем _docname_\. Одним из решений проблемы будет определение массива _n_ рядом с указателем _docname_:

```cpp
....
if (doc->isModifiedSinceSave()) {
  const gchar *docname;
  char n[64];
....
```

Аналогичные указатели:

* V507 Pointer to local array 'in\_buffer' is stored outside the scope of this array\. Such a pointer will become invalid\. inkjar\.cpp 371
* V507 Pointer to local array 'out\_buffer' is stored outside the scope of this array\. Such a pointer will become invalid\. inkjar\.cpp 375

## Неверное имя объекта в условии

**Предупреждение PVS\-Studio:** [V517](https://pvs-studio.ru/ru/docs/warnings/v517/) The use of 'if \(A\) \{\.\.\.\} else if \(A\) \{\.\.\.\}' pattern was detected\. There is a probability of logical error presence\. Check lines: 640, 643\. font\-variants\.cpp 640

```cpp
void
FontVariants::fill_css( SPCSSAttr *css ) 
{
  ....
  if( _caps_normal.get_active() ) {
    css_string = "normal";
    caps_new = SP_CSS_FONT_VARIANT_CAPS_NORMAL;
  } else if( _caps_small.get_active() ) {
    ....
  } else if( _caps_all_small.get_active() ) {
    ....
  } else if( _caps_all_petite.get_active() ) { // <=
    css_string = "petite";                     // <=
    caps_new = SP_CSS_FONT_VARIANT_CAPS_PETITE;
  } else if( _caps_all_petite.get_active() ) { // <=
    css_string = "all-petite";                 // <=
    caps_new = SP_CSS_FONT_VARIANT_CAPS_ALL_PETITE;
  } 
  ....
}
```

В условии, идущем перед _\_caps\_all\_petite\.get\_active\(\)_, имя объекта должно быть _\_caps\_petite_, а не _\_caps\_all\_petite_\.  Ошибка скорее всего произошла в результате Copy\-Paste\.

## Неаккуратное использование числовых констант

**Предупреждение PVS\-Studio:** [V624](https://pvs-studio.ru/ru/docs/warnings/v624/) The constant 0\.707107 is being utilized\. The resulting value could be inaccurate\. Consider using the M\_SQRT1\_2 constant from <math\.h\>\. PathOutline\.cpp 1198

```cpp
void
Path::OutlineJoin (....)
{
  ....
  if (fabs(c2) > 0.707107) {
    ....
  }
  ....
}
```

Такая запись не совсем корректна и может привести к уменьшению точности вычислений\. Лучше использовать математические константу _M\_SQRT1\_2_ \(the inverse of the square root of 2\), объявленную в файле _<math\.h\>_\. Думаю, на практике здесь всё работает хорошо, но захотелось обратить внимание и на такой пример некрасивого кода\.

Аналогичные предупреждения:

* V624 The constant 1\.414213562 is being utilized\. The resulting value could be inaccurate\. Consider using the M\_SQRT2 constant from <math\.h\>\. verbs\.cpp 1848
* V624 The constant 3\.14159 is being utilized\. The resulting value could be inaccurate\. Consider using the M\_PI constant from <math\.h\>\. odf\.cpp 1568
* V624 The constant 1\.414213562 is being utilized\. The resulting value could be inaccurate\. Consider using the M\_SQRT2 constant from <math\.h\>\. inkscape\-preferences\.cpp 1334

## Идентичные выражения

**Предупреждение PVS\-Studio:** [V501](https://pvs-studio.ru/ru/docs/warnings/v501/) There are identical sub\-expressions 'Ar\.maxExtent\(\) < tol' to the left and to the right of the '&&' operator\. path\-intersection\.cpp 313

```cpp
void mono_intersect(....)
{
   if(depth > 12 || (Ar.maxExtent() < tol && Ar.maxExtent() < tol)) 
   {
     ....
   }
   ....
}
```

Проверка условия _Ar\.maxExtent\(\) < tol_ выполняется дважды\. Скорее всего это получилось в результате внесения каких\-то исправлений в код\. Следует исправить выражение или просто убрать дублирующую проверку\.

Аналогичная проверка:

* V501 There are identical sub\-expressions 'Ar\.maxExtent\(\) < 0\.1' to the left and to the right of the '&&' operator\. path\-intersection\.cpp 364

## Одинаковые действия в блоках if и else

**Предупреждение PVS\-Studio:** [V523](https://pvs-studio.ru/ru/docs/warnings/v523/) The 'then' statement is equivalent to the 'else' statement\. ShapeRaster\.cpp 1825

```cpp
void Shape::AvanceEdge(....)
{
  ....
  if ( swrData[no].sens ) { 
    if ( swrData[no].curX < swrData[no].lastX ) {
      line->AddBord(swrData[no].curX,
                    swrData[no].lastX,
                    false);
    } else if ( swrData[no].curX > swrData[no].lastX ) { 
        line->AddBord(swrData[no].lastX,
                      swrData[no].curX,
                      false);
      }
  } else {
    if ( swrData[no].curX < swrData[no].lastX ) {
      line->AddBord(swrData[no].curX,
                    swrData[no].lastX,
                    false);
    } else if ( swrData[no].curX > swrData[no].lastX ) {
        line->AddBord(swrData[no].lastX,
                      swrData[no].curX,
                      false);
    }
  }
}
```

Код в блоках _if_ и _else_ одинаков, поэтому стоит просмотреть это место и либо исправить логику работы, либо удалить дублирующую ветку\.

Аналогичные места:

* V523 The 'then' statement is equivalent to the 'else' statement\. ShapeRaster\.cpp 1795
* V523 The 'then' statement is equivalent to the 'else' statement\. PathCutting\.cpp 1323
* V523 The 'then' statement is equivalent to the 'else' statement\. ShapeSweep\.cpp 2340

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

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

Предлагаю [скачать](https://pvs-studio.ru/ru/pvs-studio/download/) и попробовать PVS\-Studio на своем собственном проекте\.