Pull to refresh
0

Собираю страшненькое от программистов

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

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

Ошибки мне нужны для создания нового уникального набора правил диагностики ошибок общего типа. Правил, которые действительно актуальны, которые найдут ошибки не в абстрактных приложениях, а в данных нам в ощущениях. Неинтересно уже искать в тексте завалявшиеся случайно триграфы. Ни разу не видел ошибку, связанную с триграфом. А вот опечаток, где для очистки строки вместо 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 или через форму для связи.
Tags:
Hubs:
+45
Comments 82
Comments Comments 82

Articles

Information

Website
www.intel.ru
Registered
Founded
Employees
5,001–10,000 employees
Location
США
Representative
Анастасия Казантаева