Как одна маленькая ошибка стоила разработчикам 50 часов ее поиска
Кому нравится искать ошибки в уже написанном коде? Особенно если это копипаста или опечатка. Человеческий глаз пропустит ее в 80 случаях из 100. И нет смысла пенять на программиста (покажите этот текст своему тимлиду). Чем больше проект, тем больше шансов оставить не только такие ошибки, но и похлеще:
- переполнение буфера;
- логические ошибки;
- разыменование нулевого указателя и пр.
Их допускают даже опытные программисты. И да, их легко совершить, но трудно найти в С++.
Нужны примеры?
Вот наглядный пример такой ошибки. Не прокручивайте сразу страничку, а посмотрите на код. Как вы думаете, что здесь могло пойти не так?
if (ch >= 0x0FF00)
{
if (!((ch >= 0x0FF10) && (ch <= 0x0FF19)) ||
((ch >= 0x0FF21) && (ch <= 0x0FF3A)) ||
((ch >= 0x0FF41) && ((ch <= 0x0FF5A)))
{
if (j == 0)
continue;
ch = chx;
}
}
Теперь пояснение для тех, кто поленился искать баг. Ещё раз рассмотрим условие:
if (!((ch >= 0x0FF10) && (ch <= 0x0FF19)) ||
((ch >= 0x0FF21) && (ch <= 0x0FF3A)) ||
((ch >= 0x0FF41) && (ch <= 0x0FF5A)))
Автор кода хотел убедиться, что символ не входит ни в один из трёх диапазонов. Однако применил логический оператор NOT (!) только к первому подвыражению.
Итого:
Если выполнилось условие
!((ch >= 0x0FF10) && (ch <= 0x0FF19))
то вычисление выражения прерывается, согласно short-circuit evaluation.
Если условие не выполнилось, то значение переменной ch лежит в диапазоне [0xFF10..0xFF19]. Соответственно, четыре дальнейших сравнения не имеют смысла. Все они будут ложными или истинными:
ch >= 0x0FF21 — всегда false
ch <= 0x0FF3A — всегда true
ch >= 0x0FF41 — всегда false
ch <= 0x0FF5A — всегда true
Нужны еще примеры?
Это не единственный случай, когда маленький баг становится большой проблемой и отнимает много времени и сил разработчиков. Поиск ошибки может занять 50 часов и оказаться безуспешным (основано на реальных событиях).
Если лень читать по ссылке, то вот резюме: ошибка, на обнаружение которой было безуспешно потрачено около 50 часов, при помощи однократного запуска статического анализатора была обнаружена и исправлена менее чем за час!
Вывод
Вы уже поняли, что даже опытные программисты не застрахованы от подобных ошибок. И что самое печальное – в больших проектах не бывает "вашего" кода. И даже если для вас это очевидные ошибки, то не факт, что ваш коллега их не допустит, а в итоге баг окажется общим.
Основная польза статического анализа НЕ в том, чтобы найти одну запрятанную ошибку в день перед релизом, а в том, чтобы регулярно устранять десятки обычных ошибок, которые произошли по чьей-либо вине. Тогда и только тогда вы сможете ощутить всю полезность таких инструментов, сосредоточившись на более важных задачах, чем выискивание бага.
А чтобы удостовериться, что ваш проект в порядке, можно использовать 30-дневную триал версию.