Вебинар: Использование статических анализаторов кода при разработке безопасного ПО - 19.12
Меня не покидает когнитивный диссонанс. На форумах обсуждаются возвышенные идеи о написании сверх надежных классов, кто-то рассказывает, что его проект собирается с ключами -Wall -Wextra -pedantic -Weffc++. Господи, где все эти достижения науки и техники? Почему я вижу кругом глупейшие ошибки? Может быть, со мной что-то не так?
Нет, на самом деле я вижу и отличные проекты. Примером может служить библиотека ALGLIB. Это весьма интересная библиотека, с точки зрения кода. Пишется она на Паскале, а потом транслируется в C++, C#. Помимо прочих разных преимуществ, такой подход позволяет выловить много разных ошибок, так как одна и та же программа собирается компиляторами для разных языков. Впрочем, это отдельная история. Возможно, мы как-нибудь, напишем с автором этой библиотеки совместную заметку.
Такие приятные исключения, пожалуй, ещё больше усиливают диссонанс. Вот представьте мои ощущения. Я беру сложный пакет численного анализа и не нахожу в нем ошибок. Мне радостно за качественный код. Немного только грустно, что такому человеку PVS-Studio не продать. Ну да ладно. Беру проект OpenCOLLADA. Проверяю. WTF? Других слов я подобрать не могу. Как вам такие конструкторы?
struct short2
{
short values[2];
short2(short s1, short s2)
{
values[0] = s1;
values[2] = s2;
}
....
};
struct double2
{
double values[2];
double2( double d1, double d2)
{
values[0]=d1;
values[0]=d2;
}
....
}
В первом конструкторе промахнулись мимо массива. Во втором скопировали строчку и забыли поменять индекс.
Прости читатель, не могу удержаться от картинки. Она очень точно передает мои эмоции.
"Доставляют" и другие конструкторы. Например, вот это мило:
struct ParserString : public UnionString
{
ParserString()
{
UnionString::str = 0;
UnionString::length = 0;
}
ParserString(const int& val)
{
ParserString();
}
};
Вместо вызова другого конструктора, создается и сразу уничтожается временный объект. А члены класса остаются неинициализированными. Подробнее.
Господи, где те люди, которые, засучив рукава, пишут статьи про C++11, лямбды, Boost.Asio, shared_ptr, constexpr, LINQ. Почему я вижу в коде:
struct ObjectGroups{
componentList objectGrpCompList;
int objectGroupId;
short objectGrpColor;
void write(FILE* file) const;
}* objectGroups;
void write(FILE* file) const
{
size_t size = sizeof(objectGroups)/sizeof(ObjectGroups);
for(size_t i=0; i<size; ++i)
{
objectGroups[i].write(file);
if(i+1<size) fprintf(file," ");
}
}
Поделили размер указателя на размер структуры и получили 0. Что вообще здесь хотели сделать? WTF?
Впрочем, когда даже понятно, что и как хотели записать в файл, от этого не легче.
void write(FILE* file) const
{
fprintf(file,"%i %i %i %i ",
sDivisionCount, tDivisionCount, uDivisionCount, pointCount);
size_t size = pointCount*3;
for(size_t i; i<size; ++i)
{
fprintf(file, "%f", points[i]);
if(i+1<size) fprintf(file, " ");
}
}
Если не заметили баг, то я подскажу. Переменная 'i' не инициализируется: for(size_t i; i<size; ++i).
Извините, что поделился всем этим с вами. Мне так легче. Заодно, я естественно скажу, что эти ошибки были найдены с помощью статического анализатора кода PVS-Studio. Расположение этих и некоторых других забавных ошибок я выложил вот в этом текстовом файлике. И как всегда, если будут желающие более тщательно проверить этот проект, я готов поделиться ключиком.
Удачи и безбажного вам кода!
0