Главная
Блог разработчиков phpBB
 
+ 17 предустановленных модов
+ SEO-оптимизация форума
+ авторизация через соц. сети
+ защита от спама

Единорог заинтересовался микромиром

Anna | 24.06.2014 | нет комментариев

В данный раз увлекательные примеры ошибок нам преподнёс микромир. Мы проверили с поддержкой анализатора кода PVS-Studio открытый план лена с поддержкой диагностики: V526 The ‘memcmp’ function returns 0 if corresponding buffers are equal. Consider examining the condition for mistakes. MotorStage.cpp 385

Одинаковые сопоставления

Identical comparisons
const char* g_Out = "Out";
int FieldDiaphragm::OnCondensor(....)
{
  ....
  std::string value;
  ....
  if (value == g_Out)
    return
      g_hub.SetCondensorPosition(*this, *GetCoreCallback(), 0);
  else if (value == g_Out)
    return
      g_hub.SetCondensorPosition(*this, *GetCoreCallback(), 1);
  ....
}

2-й оператор ‘if’ содержит неправильное условие. Каким должно быть второе условие, я не знаю. Впрочем, отлично видно, что второе условие никогда не выполнится.

Диагностика, выявившая ошибку: V517 The use of ‘if (A) {…} else if (A) {…}’ pattern was detected. There is a probability of logical error presence. Check lines: 1455, 1457. LeicaDMR.cpp 1455

Есть ещё один фрагмент кода с аналогичной оплошностью. Видимо, с установкой позиции какого-то колёсика будут задачи:

class Wheel : public CStateDeviceBase<Wheel>
{
  ....
  unsigned wheelNumber_;
  ....
};

int Wheel::SetWheelPosition(int position)
{
  unsigned char cmd[4];
  cmd[0] = moduleId_; cmd[2] = 0; cmd[3] = 58;
  if (wheelNumber_ == 1) {
    switch (position) {
      case 0: cmd[1] = 49; break;
      case 1: cmd[1] = 50; break;
      case 2: cmd[1] = 51; break;
      case 3: cmd[1] = 52; break;
      case 4: cmd[1] = 53; break;
      case 5: cmd[1] = 54; break;
    }
  } else if (wheelNumber_ == 1) {
    switch (position) {
      case 0: cmd[1] = 33; break;
      case 1: cmd[1] = 64; break;
      case 2: cmd[1] = 35; break;
      case 3: cmd[1] = 36; break;
      case 4: cmd[1] = 37; break;
      case 5: cmd[1] = 94; break;
    }
  ....
}

Диагностическое сообщение PVS-Studio: V517 The use of ‘if (A) {…} else if (A) {…}’ pattern was detected. There is a probability of logical error presence. Check lines: 645, 654. Ludl.cpp 645

Кажется, мы о чём-то позабыли

Feel like we've missed something

Предлагаю посмотреть вот на данный код. Подметите, чего в нём не хватает?

class MP285
{
  ....
  static int GetMotionMode() { return m_nMotionMode; }
  ....
};

int ZStage::_SetPositionSteps(....)
{
  ....
  if (MP285::GetMotionMode == 0)
  {
    long lOldZPosSteps = (long)MP285::Instance()->GetPositionZ();
    dSec = (double)labs(lZPosSteps-lOldZPosSteps) / dVelocity;
  }
  else
  {
     dSec = (double)labs(lZPosSteps) / dVelocity;
  }
  ....
}

Не хватает дюже главной вещи. Позабыты скобочки (). Программа должна вызывать функцию GetMotionMode() и сопоставлять возвращаемое ей значение с нулём. Взамен этого с нулём сравнивается адрес функции.

Оплошность была найдена с поддержкой диагностики: V516 Consider inspecting an odd expression. Non-null function pointer is compared to null: ‘MP285::GetMotionMode == 0′. MP285ZStage.cpp 558

Одинокой странник

wanderer
int HalogenLamp::SetIntensity(long intensity)
{
  ....
  command_stream.str().c_str();
  ....
}

Что это такое? Второстепенный результат рефакторинга? Недописанный код? Безвредная лишняя строчка либо оплошность?

Есть два места, где дозволено увидеть таких одиноких странников:

  • V530 The return value of function ‘c_str’ is required to be utilized. ZeissCAN.cpp 1553
  • V530 The return value of function ‘c_str’ is required to be utilized. ZeissCAN.cpp 2800

«Брамины»

Brahmins
int LeicaScopeInterface::GetDICTurretInfo(....)
{
  ....
  std::string tmp;
  ....
  if (tmp == "DIC-TURRET")
    scopeModel_->dicTurret_.SetMotorized(true);
  else
    scopeModel_->dicTurret_.SetMotorized(true);
  ....
}

Вот так выглядит программный “брамин“. Самостоятельно, выполнится условие либо нет, выполняется один и тот же код.

Предупреждение: V523 The ‘then’ statement is equivalent to the ‘else’ statement. LeicaDMIScopeInterface.cpp 1296

Ещё одна оплошность схожего рода. Тут сравниваются идентичные строки. Вероятно,данный код содержит опечатку:

int XLedDev::Initialize()
{
  ....
  if (strcmp(
    XLed::Instance()->GetXLedStr(XLed::XL_WLedDevName  
                                 m_nLedDevNumber).c_str(),
    XLed::Instance()->GetXLedStr(XLed::XL_WLedDevName  
                                 m_nLedDevNumber).c_str()
            ) != 0)
  ....
}

Предупреждение: V549 The first argument of ‘strcmp’ function is equal to the second argument. XLedDev.cpp 119

Что-то не стыкуется

A mismatch

Значения ‘false’ и ‘true’ могут неявно приводиться к типу ‘int’:

  • false превращается в 0;
  • true превращается в 1.

Скажем, вот такой код удачно скомпилируется:

int F() { return false; }

Функция F() возвращает 0.

Изредка люди заблуждаются и взамен ранга ошибки, тот, что имеет тип ‘int’, возвращают ‘false’ либо ‘true’. Происходит это по забывчивости. Ничего ужасного, если ранг ошибки кодируется значением 0.

Напасть появляется в том случае, если ранги ошибок кодируются значениями, хорошими от нуля. Именно это происходит в плане pe. Prior.cpp 2313

  • V601 The ‘false’ value is implicitly casted to the integer type. Prior.cpp 2322
  • V601 The ‘false’ value is implicitly casted to the integer type. SutterLambda.cpp 190
  • V601 The ‘false’ value is implicitly casted to the integer type. SutterLambda.cpp 269
  • V601 The ‘false’ value is implicitly casted to the integer type. SutterLambda.cpp 285
  • V601 The ‘false’ value is implicitly casted to the integer type. Tofra.cpp 900
  • V601 The ‘false’ value is implicitly casted to the integer type. Tofra.cpp 1806
  • V601 The ‘false’ value is implicitly casted to the integer type. Tofra.cpp 1830

Необычный Get

Strange
int pgFocus::GetOffset(double& offset)
{
  MM_THREAD_GUARD_LOCK(&mutex);
  deviceInfo_.offset = offset;
  MM_THREAD_GUARD_UNLOCK(&mutex);
  return DEVICE_OK;
}

Мне кажется, либо с эти кодом что-то не в порядке?

Анализатору данный код не нравится: V669 The ‘offset’ argument is a non-constant reference. The analyzer is unable to determine the position at which this argument is being modified. It is possible that the function contains an error. pgFocus.cpp 356

И подлинно, необычно. Функция именуется «Get____». Функция возвращает ранг. А ещё она принимает довод ‘offset’ по ссылке. И… И не записывает ничего в него. Я не знаю, как всё это работает. Но, быть может, нужно было сделать присваивание напротив? Как-то так:

offset = deviceInfo_.offset;

Ещё одна подозрительная функция GetTransmission():

int SpectralLMM5Interface::GetTransmission(....,
                                           double& transmission)
{
  ....
  int16_t tr = 0;
  memcpy(&tr, answer   1, 2);
  tr = ntohs(tr);
  transmission = tr/10;
  ....
}

Предупреждение PVS-Studio: V636 The ‘tr / 10′ expression was implicitly casted from ‘int’ type to ‘double’ type. Consider utilizing an explicit type cast to avoid the loss of a fractional part. An example: double A = (double)(X) / Y;. SpectralLMM5Interface.cpp 198

Обратите внимание, что возвращаемое значение имеет тип double (речь идёт о transmission). Но вычисляется это значение необычно. Целочисленное значение делится на 10. У меня есть мощное сомнение, что происходит потеря точности. Скажем, если ‘tr’ равно 5, то позже деления мы получим 0, а совсем не 0.5.

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

transmission = tr/10.0;

Оплошность либо не оплошность? Первое ощущение может быть лживо.

Error or not?

В языке Си/Си , числа начинающиеся с нуля считаются заданными в восьмеричном формате. В плане ! int ret = DEVICE_OK; …. if (ret != DEVICE_OK) return ret; AddAllowedValue(“DichroicMirrorIn”, “0″, 0); AddAllowedValue(“DichroicMirrorIn”, “1″, 1); if (ret != DEVICE_OK) return ret; …. }
Вторая проверка вновь не имеет. Перед ней переменная ‘ret’ нигде не изменится. Вторую проверку дозволено отважно удалить.

Таких лишних проверок довольно много. Приведу их списком: Micro-Manager-V571-V649.txt.

Ещё из мелочи дозволено подметить неправильной формат при работе с функциями sprintf(). Беззнаковая переменная распечатывается, как знаковая. Это может привести к некорректной распечатке крупных значений.

int MP285Ctrl::Initialize()
{
  ....
  unsigned int nUm2UStepUnit = MP285::Instance()->GetUm2UStep();
  ....
  sprintf(sUm2UStepUnit, "%d", nUm2UStepUnit);
  ....
}

Нашлось три таких места:

  • V576 Incorrect format. Consider checking the third actual argument of the ‘sprintf’ function. The SIGNED integer type argument is expected. MP285Ctrl.cpp 253
  • V576 Incorrect format. Consider checking the third actual argument of the ‘sprintf’ function. The SIGNED integer type argument is expected. MP285Ctrl.cpp 276
  • V576 Incorrect format. Consider checking the third actual argument of the ‘sprintf’ function. The SIGNED integer type argument is expected. MP285Ctrl.cpp 327

Завершение

Единичная проверка этого и всякого иного плана непроизводительна. Пользу дозволено получить только при регулярном применении статических анализаторов кода. Тогда многие ошибки и опечатки будут справлены на самом раннем этапе. Рассматривайте статический обзор, как растяжение предупреждений, которые выдаёт компилятор.

Командам, создающих средние и огромные планы для операционной системы Windows, мы рекомендуем применять наш статический анализатор PVS-Studio. Цена зависит от размера команды и требуемого яруса поддержки.

Для маленьких команд и индивидуальных разработчиков мы предлагаем инструмент CppCat. Индивидуальная лицензия — $250. Продление — $200. При покупке нескольких лицензий — скидки.

Тем, кто работает с Linux, мы предлагаем обратить внимание на безвозмездный анализатор кода Cppcheck. Либо испробовать Standalone версию PVS-Studio.

P.S.

Перевод этой статьи: “The Unicorn’s Travel to the Microcosm“.

Прочитали статью и есть вопрос?

Зачастую к нашим статьям задают одни и те же вопросы. Результаты на них мы собрали тут: Результаты на вопросы читателей статей про PVS-Studio и CppCat, версия 2014. Пожалуйста, ознакомьтесь со списком.

 

Источник: programmingmaster.ru

 

Оставить комментарий
Форум phpBB, русская поддержка форума phpBB
Рейтинг@Mail.ru 2008 - 2017 © BB3x.ru - русская поддержка форума phpBB