Pull to refresh
612
17
Андрей Карпов @Andrey2008

Директор по развитию бизнеса

Send message
Бегло посмотрел отчёт. Предупреждений мало и те в основном — это ложные срабатывания. Так что с точки зрения статического анализа, качество кода можно похвалить. Можно, конечно, побурчать про то, что не выполняется проверка указателя после вызова malloc:
items->md->msg_type_data = (char*) malloc(msg_type_len+1);
strcpy( items->md->msg_type_data, msg_type_ );

Но зато зачем-то есть после оператора new:
msg_def_items * items = new msg_def_items;
if ( !items )
  return 0;

И тому подобное. Но это не очень интересно, и в целом из найденного статью написать сложно.
The story turned out to have another continuation: www.viva64.com/en/b/0802
Интересуют примеры утечек, которые не видит PVS-Studio. Впрочем, по описанию, подозреваю, что и не получится. :)
Спасибо за интересную публикацию. Да, я и сам отмечал в статье, что статические анализаторы явно проигрывают динамическим в поиске утечек памяти. Жаль, что на данном проекте PVS-Studio проиграл совсем уж всухую :). А можно познакомиться с примерами найденных ошибок? Интересно посмотреть, можно ли будет подтянуть анализатор для выявления хотя бы части утечек. Если код приватен, то можно переместиться в почту. А можно здесь пообсуждать разные случаи. На ваше усмотрение и заранее спасибо.

P.S. И так уж получилось, что вчера я тоже опубликовал статью, касающуюся Qt 6. Статья хорошо показывает, что хоть с утечками и не очень, зато других ошибок можно найти на любой вкус и цвет. :) Приглашаю читателей: Обработка дат притягивает ошибки или 77 дефектов в Qt 6.
Код от этого правильным не становится. :)
Про аннотирование функций я рассказываю, например, здесь: Опыт разработки статического анализатора кода (23:40). Там и про примеры библиотек есть.

По поводу изменения в библиотека — пока никак ничего не делается. Да и проблемы, собственно, нет. Функции, которые мы аннотируем, вряд ли кто-то будет менять. Никто не меняет интерфейс таких функции, как memcpy, malloc или std::swap. Если же мы про что-то экзотичное, то да, может что-то поменяться. В этом случае из-за изменения количества или типов аргументов, функция перестанет распознаваться как размеченная. И что-то может перестать ловиться. Но это столь маловероятное… Плюс если кто-то или мы сами заметим — то исправим.
Затянул с оформлением материалов в виде статьи, но вот: Дорожная карта PVS-Studio на 2021 год.
Не так посмотрел и был не прав.
image
image
Это оказывается из-за IntelliSense вылезает. Однако, смотреть лог Visual C++ всё равно сложно. Например, он здесь ложно предупреждает о потенциально неинициализированной переменных SARI, Critical, CritRecov.
double SARI, Critical, CritRecov, incSARI, incCritical, incCritRecov, sc1, sc2double SARI, Critical, CritRecov, incSARI, incCritical, incCritRecov, sc1, sc2,sc3,sc4; //this stuff corrects bed prevalence for exponentially distributed time to test results in hospital
sc1 = (P.Mean_TimeToTest > 0) ? exp(-1.0 / P.Mean_TimeToTest) : 0.0;
sc2 = (P.Mean_TimeToTest > 0) ? exp(-P.Mean_TimeToTestOffset / P.Mean_TimeToTest) : 0.0;
sc3 = (P.Mean_TimeToTest > 0) ? exp(-P.Mean_TimeToTestCriticalOffset / P.Mean_TimeToTest) : 0.0;
sc4 = (P.Mean_TimeToTest > 0) ? exp(-P.Mean_TimeToTestCritRecovOffset / P.Mean_TimeToTest) : 0.0;
incSARI = incCritical = incCritRecov = 0;
for (i = 0; i < P.NumSamples; i++)
{
  if (i > 0)
  {
    SARI = (TSMean[i].SARI - TSMean[i - 1].SARI) * sc2 + SARI * sc1;   /// <<< C4701
    Critical = (TSMean[i].Critical - TSMean[i - 1].Critical) * sc3 + Critical * sc1; /// <<< C4701
    CritRecov = (TSMean[i].CritRecov - TSMean[i - 1].CritRecov) * sc4 + CritRecov * sc1; /// <<< C4701
    incSARI = TSMean[i].incSARI * (1.0 - sc2) + incSARI * sc1;
    incCritical = TSMean[i].incCritical * (1.0 - sc3) + incCritical * sc1;
    incCritRecov = TSMean[i].incCritRecov * (1.0 - sc4) + incCritRecov * sc1;
  }
  else
  {
    SARI = TSMean[i].SARI * sc2;
    Critical = TSMean[i].Critical * sc3;
    CritRecov = TSMean[i].CritRecov * sc4;
  }

Как следствие, быстро теряется желание всё это изучать.
Теоретически, да :). На практике, /W4 даёт на проекте 828 предупреждения. В случае PVS-Studio, имеем 139 предупреждений общего назначения для всех трёх уровней. Уже легче. А если учесть, что 3 самых интересных сообщения живут на первом уровне достоверности, то становится понятно, почему ошибка ждала PVS-Studio, не смотря на то, что Visual C++ теоретически тоже может… ;)
image
By the way, there is also such a funny fragment:
void DigitalContactTracingSweep(double t)
{
  ....
  //check every day to see if contacts become index cases - but they have to be infectious. Otherwise we could set the trigger time and cause their contacts to be traced when they are not being traced themselves.
  if ((Hosts[contact].index_case_dct == 0) && (
    Hosts[contact].is_infectious_almost_symptomatic() ||
    Hosts[contact].is_case() ||
    Hosts[contact].is_infectious_almost_symptomatic()))
  ....
}

The PVS-Studio warning: V501 [CWE-570] There are identical sub-expressions 'Hosts[contact].is_infectious_almost_symptomatic()' to the left and to the right of the '| | ' operator. Sweep.cpp 1354
The is_infectious_almost_symptomatic function is constant and does not change anything:
bool Person::is_infectious_almost_symptomatic() const
{
  return this->inf == InfStat::InfectiousAlmostSymptomatic;
}

So, there's no point in calling it twice for sure. Another matter is that it may not be the error but just an accidentally duplicated check. But maybe it's the error. Nearby there is the following code:
if (Hosts[contact].is_infectious_asymptomatic_not_case() ||
  Hosts[contact].is_case() ||
  Hosts[contact].is_infectious_almost_symptomatic())

To tell more precisely, I need, for sure, to perceive the project. I can't understand it superficially.
Кстати, там ещё вот такой забавный фрагмент есть:
void DigitalContactTracingSweep(double t)
{
  ....
  //check every day to see if contacts become index cases - but they have to be infectious. Otherwise we could set the trigger time and cause their contacts to be traced when they are not being traced themselves.
  if ((Hosts[contact].index_case_dct == 0) && (
    Hosts[contact].is_infectious_almost_symptomatic() ||
    Hosts[contact].is_case() ||
    Hosts[contact].is_infectious_almost_symptomatic()))
  ....
}

Предупреждение PVS-Studio: V501 [CWE-570] There are identical sub-expressions 'Hosts[contact].is_infectious_almost_symptomatic()' to the left and to the right of the '||' operator. Sweep.cpp 1354
Функция is_infectious_almost_symptomatic константная и ничего не изменяет:
bool Person::is_infectious_almost_symptomatic() const
{
  return this->inf == InfStat::InfectiousAlmostSymptomatic;
}

Так что два раза её звать точно смысла нет. Другое дело, что может это и не ошибка, а просто случайно продублированная проверка. А может и ошибка. По соседству вот такой код есть:
if (Hosts[contact].is_infectious_asymptomatic_not_case() ||
  Hosts[contact].is_case() ||
  Hosts[contact].is_infectious_almost_symptomatic())

Чтобы судить точнее, нужно, конечно, разбираться в проекте. Вот так со стороны непонятно.
И ещё :). Продолжаем тему доверия к анализу данных в научных исследований: Исследование COVID-19 и неинициализированная переменная.

Information

Rating
429-th
Works in
Date of birth
Registered
Activity

Specialization

Specialist
C++
C
Software development