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

Copy-Paste и мюоны

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

PVS-Studio, CERN

Теперь я буду рассказывать и показывать на примерах, отчего физики тоже обязаны применять инструменты статического обзора кода. Мне бы хотелось, Дабы этим инструментом был PVS-Studio. Но, безусловно, всякий иной инструмент тоже будет пригоден. Анализатор кода сократит время на отладку приложений и уменьшит головные боли от тупых ошибок. Отменнее побольше думать о физике и поменьше об ошибках в программах на языке Си .

Грустная предыстория

На самом деле, эта статья получилась «мимо». Ошибки делает даже тот, кто ищет чужие ошибки. :)

Я недосмотрел. Я возложил подготовить план Geant4 для проверки новому молодому работнику. Нужно было скачать начальные коды, сгенерировать план для Visual Studio и вообще сделать всё нужное, Дабы я мог взять и проверить. Он всё это сделал. Вот только взял первую попавшуюся древнюю версию Geant4_9_4, которая описывалась в статье, посвященной сборке плана в Windows. Эх! Я узнал про это, теснее когда написал эту статью.

Однако, у этого есть и позитивная сторона. Я написал новую статью “Продолжение проверки Geant4“, где анализируется свежий начальный код (версия 10.0-beta). Сейчас дозволено узнать, какие ошибки были поправлены, а значит, могли бы быть обнаружены гораздо прежде и легче с поддержкой статического обзора. И дозволено увидеть ошибки, которые до сих пор скрываются. 

Из перечисленных в статье шестнадцати предупреждений в новой версии:

  • исчезло: 6
  • осталось: 10

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

Вступление

Я продолжаю серию заметок, посвященных обзору кода, используемого в научных целях. Предыдущие заметки:

В данный раз на очереди план Geant4. Приведу изложение плана, взятое из Wikipedia:

Geant4 (англ. GEometry ANd Tracking — геометрия и трекинг) — программа для моделирования прохождения элементарных частиц через вещество с применением способов Монте-Карло. Разработана в CERN на объектно-ориентированном языке программирования С . Является последующим становлением предыдущих версий GEANT, значительно переработанным и дополненным.

Как заявлено на официальном сайте плана, «области использования включают в себя физику высоких энергий и изыскание ядерных реакций, медицину, ускорители частиц, и космические физические изыскания». ПО применяется во многих исследовательских планах по каждому миру.

Сайт плана: http://geant4.org. План имеет средний размер: 76 мегабайт начального кода. Для сопоставления:

  • план VirtualDub — 13 мегабайт;
  • план Apache HTTP Server — 26 мегабайт;
  • план Chromium (совместно с дополнительными библиотеками) — 710 мегабайт.

Для обзора был использован анализатор кода PVS-Studio. Так как план Geant4 не небольшой, шанс обнаружить в нём увлекательное был дюже крупен. Не обнаружить ошибок дозволено только в маленьких планах (см. о нелинейной плотности ошибок). Бывают, безусловно, и огромные планы, где PVS-Studio ничего не находит. Жалко, но это только исключение.

Сразу хочу попросить помилования, если нечаянно написал какую-то бессмысленность, касающуюся физики. Но обратите внимание, что я сумел обнаружить ошибки в программном обеспечении, не понимая суть партонов, да и вообще примерно каждого касающегося ядерных реакций!

Прpermark! …. }
Предупреждение PVS-Studio: V501 There are identical sub-expressions ‘trk1.GetDefinition() == G4Neutron::Neutron()’ to the left and to the right of the ‘||’ operator. G4had_im_r_matrix g4mesonabsorption.cc 285

Да, я не знаю, что делает эта функция. Но, как мне кажется, на вход она получает две траектории движения элементарных частиц. Функция должна обработать специальным образом обстановку, если правда бы одна частица являются нейтронами. Но, на самом деле, проверятся только первая частица.

Видимо, на самом деле, планировали написать:

trk1.GetDefinition() == G4Neutron::Neutron() ||
trk2.GetDefinition() == G4Neutron::Neutron() 


Аналогичную опечатку дозволено найти тут: g4scatterer.cc 138

Примечание. Оплошность поправлена в новой версии Gint4. Либо данный код удалён.

 

Добавление партона


Существует функция InsertParton(), которая вставляет в контейнер партон. Дозволено указать, позже какого партона необходимо вставить новейший элемент. Если место вставки не указано, то, вероятно, дозволено вставить куда желательно. Но как раз данный случай реализован некорректно.

typedef std::vector<G4Parton *> G4PartonVector;

inline void G4ExcitedString::InsertParton(
  G4Parton *aParton, const G4Parton * addafter)
{
  G4PartonVector::iterator insert_index;
  ....
  if ( addafter != NULL ) 
  {
    insert_index=std::find(thePartons.begin(),
                           thePartons.end(), addafter);
    ....
  }
  thePartons.insert(insert_index 1, aParton);
}


Предупреждение PVS-Studio: V614 Potentially uninitialized iterator ‘insert_index’ used. g4excitedstring.hh 193

Если указатель ‘addafter’ равен нулю, то итератор «insert_index» остаётся неинициализированным. В итоге, вставка нового элемента может привести к непредвиденным итогам.

Примечание. Оплошность по-бывшему присутствует в новой версии Gint4.

 

Обработка не всех нуклонов


Нуклоны — всеобщее наименование для протонов и нейтронов.

Имеется функция packNucleons(), которая обрабатывает не все элементы. Дело в том, что цикл завершается сразу позже первой итерации. В конце тела цикла имеется оператор ‘break’, но при этом нигде нет оператора ‘continue’.

void G4QMDGroundStateNucleus::packNucleons()
{
  ....
  while ( nmTry < maxTrial )
  {
    nmTry  ;
    G4int i = 0; 
    for ( i = 1 ; i < GetMassNumber() ; i   )
    {
      ....
    }
    if ( i == GetMassNumber() ) 
    {
      areTheseMsOK = true;
    }
    break;
  }
  ....
}


Предупреждение PVS-Studio: V612 An unconditional ‘break’ within a loop. g4qmdgroundstatenucleus.cc 274

Мне кажется, оператор ‘break’ в конце легко ненужный и написан нечаянно.

Примечание. Оплошность по-бывшему присутствует в новой версии Gint4.

 

Lund string model и опечатка в индексе


In particle physics, the Lund string model is a phenomenological model of hadronization.

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

G4LundStringFragmentation::G4LundStringFragmentation()
{
  ....
  BaryonWeight[0][1][2][2]=pspin_barion*0.5;
  ....
  BaryonWeight[0][1][2][2]=(1.-pspin_barion);
  ....
}


Предупреждение PVS-Studio: V519 The ‘BaryonWeight[0][1][2][2]‘ variable is assigned values twice successively. Perhaps this is a mistake. Check lines: 205, 208. g4lundstringfragmentation.cc 208

Примечание. Хочу подметить, что в коде мне встретилось уйма мест, где переменной два раза подряд присваиваются разные значения. Многие места абсолютно безвредны. Скажем, в начале, переменным присваивается 0, а после этого теснее реальное значение. Впрочем, многие из таких мест могут содержать ошибку. Следственно я рекомендую авторам Geant4 наблюдательно отнестись к диагностическим предупреждениям V519. Сам я просмотрел эти предупреждения дюжеповерхностно.

Кстати, не дюже внятен подход, когда сначала переменная инициализируется значением по умолчанию, а после этого теснее необходимым значением. Для чего это необходимо? Проще сразу объявлять переменную там, где она необходима, и инициализировать необходимым числом.

Примечание. Оплошность по-бывшему присутствует в новой версии Gint4.

 

Некоторые другие предупреждения V519


Сомнительно смотрится оператор копирования в классе G4KineticTrack:

const G4KineticTrack& G4KineticTrack::operator=(
  const G4KineticTrack& right)
{
  ....
  the4Momentum = right.the4Momentum;  
  the4Momentum = right.GetTrackingMomentum();
  ....
}


Предупреждение PVS-Studio: V519 The ‘the4Momentum’ variable is assigned values twice successively. Perhaps this is a mistake. Check lines: 451, 452. g4kinetictrack.cc 452

Примечание. Оплошность по-бывшему присутствует в новой версии Gint4.

Кстати, на конструкторы вообще было много предупреждений V519. Быть может, в таком коде есть толк? Скажем, для целей отладки. Непостижимо. Так что думаю, стоит привести ещё пару примеров подозрительного кода:

void G4IonisParamMat::ComputeDensityEffect()
{
  ....
  fX0density = 0.326*fCdensity-2.5 ;
  fX1density = 5.0 ;
  fMdensity = 3. ; 
  while((icase > 0)&&(fCdensity < ClimiG[icase])) icase-- ;
  fX0density = X0valG[icase];
  fX1density = X1valG[icase];
  ....
}


Предупреждения PVS-Studio: V519 The ‘fX0density’ variable is assigned values twice successively. Perhaps this is a mistake. Check lines: 245, 247. g4ionisparammat.cc 247

V519 The ‘fX1density’ variable is assigned values twice successively. Perhaps this is a mistake. Check lines: 245, 247. g4ionisparammat.cc 247

Примечание. Оплошность по-бывшему присутствует в новой версии Gint4.

void G4AdjointPhotoElectricModel::SampleSecondaries(....)
{ 
  ....
  pre_step_AdjointCS = totAdjointCS;
  post_step_AdjointCS =
    AdjointCrossSection(aCouple, electronEnergy,IsScatProjToProjCase);
  post_step_AdjointCS = totAdjointCS; 
  ....
}


Предупреждение PVS-Studio: V519 The ‘post_step_AdjointCS’ variable is assigned values twice successively. Perhaps this is a mistake. Check lines: 76, 77. g4adjointphotoelectricmodel.cc 77

Примечание. Оплошность по-бывшему присутствует в новой версии Gint4.

И конечный, подмеченный мною подозрительный фрагмент. Обратите внимание на член ‘erecrem’.

void G4Incl::processEventIncl(G4InclInput *input)
{
  ....
  varntp->mzini = izrem;
  varntp->exini = esrem;
  varntp->pxrem = pxrem;
  varntp->pyrem = pyrem;
  varntp->pzrem = pzrem;
  varntp->mcorem = mcorem;
  varntp->erecrem = pcorem;
  varntp->erecrem = erecrem;
  ....
}


Предупреждение PVS-Studio: V519 The ‘varntp->erecrem’ variable is assigned values twice successively. Perhaps this is a mistake. Check lines: 896, 897. g4incl.cc 897

Примечание. Оплошность поправлена в новой версии Gint4. Либо данный код удалён.

 

Счет элементов массива с 1


Мне кажется, тут кто-то на миг позабыл, что элементы массивов в Си нумеруются с нуля. В итоге, может случиться выход за рубеж массива. Плюс отсутствует сопоставление со значением 1.4, расположенным в самом начале массива.

void
G4HEInelastic::MediumEnergyClusterProduction(....)
{
  ....
  G4double alem[] = {1.40, 2.30, 2.70, 3.00, 3.40, 4.60, 7.00};
  ....
  for (j = 1; j < 8; j  ) {
    if (alekw < alem[j]) {
      jmax = j;
      break;
    }
  }  
  ....
}


Предупреждение PVS-Studio: V557 Array overrun is possible. The value of ‘j’ index could reach 7. g4heinelastic.cc 4682

Примечание. Оплошность по-бывшему присутствует в новой версии Gint4.

 

Физика и undefined behavior


Си безжалостный язык. Чуть-чуть расслабился — и здесь же отстрелил себе протоном ногу. Причем, сразу это дозволено и не подметить. Вот пример неправильного реализованного оператора сложения:

template <typename T> GMocrenDataPrimitive<T> & 
GMocrenDataPrimitive<T>::operator  
  (const GMocrenDataPrimitive<T> & _right)
{
  GMocrenDataPrimitive<T> rprim;
  ....
  return rprim;
}


Предупреждение PVS-Studio: V558 Function returns the reference to temporary local object: rprim. G4GMocren g4gmocrenio.cc 131

Функция возвращает ссылку на локальный объект. Попытка трудиться с этой ссылкой приведёт к неопределенному поведению.

Примечание. Оплошность по-бывшему присутствует в новой версии Gint4.

 

Пора закругляться


К сожалению, экскурсию в мир физики пора заканчивать. Дело в том, что это всё-таки статья, а не многостраничный отчёт. Жалко, что я не поспел рассказать про многие другие ошибки. Больше детально познакомиться с подозрительным кодом, тот, что я поспел подметить, просматривая диагностические предупреждения PVS-Studio, дозволено в этом файле — geant4_old.txt.

Только умоляю не делать итог, что это все ошибки, тот, что сумел обнаружить PVS-Studio. Я глядел отчёт довольно поверхностно и мог много чего пропустить. Умоляю разработчиков плана проверить код с поддержкой PVS-Studio самосильно. Напишите нам, и мы выделим для этого ключ на некоторое время.

Ну и безусловно, как неизменно повторюсь, что результативнее применять статический обзор кода регулярно, а не от случая к случаю. Дабы понять значимость регулярного применения, дюже умоляю почитать тут и тут.

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

Единственно, хочу коротко пояснить диагностики V636 и V624. Изредка они могут свидетельствовать о неточности в вычислениях. Мне кажется, эти диагностики главны, когда речь идёт о вычислительных программах.

Пример диагностики V636:

G4double G4XAqmTotal::CrossSection(
  const G4KineticTrack& trk1, const G4KineticTrack& trk2) const
{
  ....
  G4int sTrk1 = ....;
  G4int qTrk1 = ....;

  G4double sRatio1 = 0.;
  if (qTrk1 != 0) sRatio1 = sTrk1 / qTrk1;
  ....
}


Предупреждение PVS-Studio: V636 The ‘sTrk1 / qTrk1′ 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;. g4xaqmtotal.cc 103

Итог деления «double X = 3/2» равен 1, а не 1.5 как может показаться из-за невнимательности. В начале, происходит целочисленное деление, а теснее после этого итог превращается в тип ‘double’. Рассматривая неизвестный код, сложно сказать, необходимо ли подлинно применять целочисленное деление либо это оплошность. Думаю, такие места в Geant4 заслуживают внимания.

Примечание. Если требуется именно целочисленное деление, такие места стоит сопровождать комментарием.

Пример диагностики V624:

dSigPodT = HadrTot*HadrTot*(1 HadrReIm*HadrReIm)*
   (....)/16/3.1416*2.568;


Предупреждение PVS-Studio: V624 The constant 3.1416 is being utilized. The resulting value could be inaccurate. Consider using the M_PI constant from <math.h>. g4elastichadrnucleushe.cc 750

Непостижимо, отчего массово применяются суровые константы для обозначения числа Пи, Пи/2 и так дальше. Готов уверовать, что точности абсолютно хватает. Но всё равно, это не трактование. Такие константы — ненужный причина для опечаток и неточностей. Есть масса предопределенных констант, таких как M_PI, M_PI_4, M_LN2. PVS-Studio выдаёт соответствующие рекомендации по замене жестких констант.

Чуть не позабыл. В файле geant4_old.txt я также привёл сообщения, относящиеся к микрооптимизациям. Скажем, по поводу инкремента итераторов:

class G4PhysicsTable : public std::vector<G4PhysicsVector*> {
  ....
};

typedef G4PhysicsTable::iterator G4PhysicsTableIterator;

inline
 void  G4PhysicsTable::insertAt (....)
{
  G4PhysicsTableIterator itr=begin();
  for (size_t i=0; i<idx;   i) { itr  ; }
  ....
}


Предупреждение PVS-Studio: V803 Decreased performance. In case ‘itr’ is iterator it’s more effective to use prefix form of increment. Replace iterator with iterator. g4physicstable.icc 83

Подобнее, отчего данный стоит изменить, описано в статье: Есть ли утилитарный толк применять для итераторов префиксный оператор инкремента it, взамен постфиксного it .

 

Завершение


Смиритесь, что ошибки и опечатки допускают все. И да, даже вы, уважаемые читатели. Это неминуемо. Применяя инструменты статического обзора кода, дозволено поправить уйма ошибок на самых ранних этапах. Это сократит время, нужное на поиск недостатков и дозволит большее внимание уделить непринужденно решаемой задачи.

 

Добавочные ссылки


  1. Андрей Карпов. Мифы о статическом обзоре. Миф 2-й — высокопрофессиональные разработчики не допускают тупых ошибок.
  2. Андрей Карпов. Результаты на вопросы, которые Зачастую задают позже прочтения наших статей.
  3. Новости о языке Си , увлекательные статьи и информация о испытанных нами планах:@Code_Analysis.
  4. Первое знакомство с анализатором: PVS-Studio для Visual C .

 

 

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

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