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

Мне интересны в первую очередь паттерны ошибок, допускаемых в программах на Си++. Но я сознательно не стал помещать этот пост в раздел «Си++». Приводите примеры ошибок из других языков. Часто рассматривая ошибку, ��ожно придумать ее аналог на другом языке.

Ошибки мне нужны для создания нового уникального набора правил диагностики ошибок общего типа. Правил, которые действительно актуальны, которые найдут ошибки не в абстрактных приложениях, а в данных нам в ощущениях. Неинтересно уже искать в тексте завалявшиеся случайно триграфы. Ни разу не видел ошибку, связанную с триграфом. А вот опечаток, где для очистки строки вместо str.clear() написано str.empty(), полным-полно. Например, я писал про такой пример здесь. И ведь такие ошибки не находятся существующими инструментами! Поэтому мы и идем по пути создания нового, а не повторения старого.

Теперь попробую пояснить, про какие же ошибки мне хочется услышать и как.



Начну с примера самой банальной опечатки.
double a;
a = 1,536;

Вместо точки случайно написана запятая. В результате данная строчка эквивалентна "(a = 1), 536;" и переменная 'a' примет значение 1. Компилятор естественно промолчит (по крайней мере, Visual C++).

Уверен, многие уже готовят в голове комментарий на тему, что такую ошибку может сделать только школьник. Зря. Никто не застрахован от таких ошибок. Эту ситуацию описал один из лучших специалистов по программированию, которых я знаю. Это Дмитрий Вьюков, обладатель титула «Мастер программирования, Черный пояс Intel». Автор множества статей и проекта Relacy Race Detector.

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

Пойдем дальше. Очень легко забыть, что std::remove() не удаляет элементы, а только сдвигает их. И как следствие должен использоваться в паре с функций erase(). Про это сделала хорошую заметку Елена Сагалаева (автор блога «Алёна C++»): "std::remove и std::remove_if на самом деле ничего не удаляют".

Эта также распространенная, красивая, актуальная, высокоуровневая ошибка. Она мне очень нравится. В реальном приложении она может выглядеть так (библиотека ZThreads):

void unregisterThread() {
  Guard<TaskQueue> g(_taskQueue);
  std::remove(_threads.begin(), _threads.end(), ThreadImpl::current());
}

Этот фрагмент был найден PVS-Studio, после реализации соответствующей проверки, созданной после прочтения статьи Алёны.

Следующее правило придумал я сам, основываясь на личном опыте. Бывало, да и сейчас бывает, что я делаю опечатки и использую не то имя переменной. Некоторые такие ошибки можно выявить автоматически. Например, подозрительно, когда одной переменной подряд присваивается разное значение. После реализации соответствующей диагностики с помощью PVS-Studio сразу обнаружилось, например, такая ошибка в библиотеке Win32++:

class CSize : public SIZE
{
  ...
  CSize(POINT pt) { cx = pt.x;  cx = pt.y; }

Приведу пример еще одного обсуждения, из которого можно составить правило для статического анализа. Вот здесь люди долго не могли понять, что через указатель на базовый класс нельзя работать с массивом производных классов. И как это обычно бывает, винили «глючный компилятор». В дискуссии с толку может сбить обсуждение оператора delete, поэтому приведу свой пример:

class A
{
  int a;
};

class B : public A
{
  int b;
};

void FOO()
{
  B array[5];
  A *p = array;
  p[3].a = 1; //Пишем не пойми куда
}

Размер классов A и B различен, а, следовательно, array[i] и p[i] адресуются к различным участкам памяти.

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

Я описал разные примеры, как на основе обсуждений в форумах, статей, личном опыте, можно составить интересные правила анализа. Я буду рад, если вы поделитесь своими примерами или ссылками на подобные примеры.

P.S.

Если вам недоступна возможность комментирования статьи, то прошу писать мне на ящик karpov[@]viva64.com или через форму для связи.