О пользе или вреде комментариев в коде программ много говорится и однозначного мнения так и не сформировалось. Однако мы решили посмотреть на них с другой стороны. Могут ли комментарии навести исследователя на скрытые ошибки в коде?
При изучении различных проектов на предмет ошибок, было замечено, что программисты иногда замечают дефекты, но не могут до конца разобраться в их причинах. Нередко подозрение падает на компилятор. Про этот эффект недавно писал мой коллега в статье "Во всём виноват компилятор". В результате, программист делает в коде подпорку и оставляет различные комментарии. Часто эти комментарии нецензурного характера.
Мы решили, что это интересная сфера для исследований. Просматривать файлы вручную или искать обычным поиском по одному слову это очень долгий и утомительный процесс. Была написана утилита, которая ищет в ".c" и ".cpp" файлах подозрительные комментарии, основываясь на своем словаре "подозрительных слов". Например, в словарь подозрительных слов попали: fuck, bug, stupid, compiler.
Было получено очень большое количество строк с такими комментариями. Поиск фрагментов действительно стоящих внимания, стал непростым и утомительным занятием. Удалось найти мало интересного. Намного меньше, чем хотелось.
Задачей поиска было нахождение новых шаблонов возможных ошибок, которые допускают программисты. К сожалению, все места, которые были найдены или не диагностируемы статическим анализом кода или уже успешно обнаруживаются PVS-Studio.
Плохой результат, тоже результат. Скорее всего, мы сделаем вывод, что метод поиска странных комментариев тупиковый. Он слишком трудоёмок и позволяет найти совсем немного ляпов.
Но раз исследование проведено, мы решили поделиться парой примеров с вами.
Например, такой пример кода:
// Search for EOH (CRLFCRLF)
const char* pc = m_pStrBuffer;
int iMaxOff = m_iStrBuffSize - sizeof(DWORD);
for (int i = 0; i <= iMaxOff; i++) {
if (*(DWORD*)(pc++) == 0x0A0D0A0D) {
// VC-BUG?: '\r\n\r\n' results in 0x0A0D0A0D too,
//although it should not!
bFoundEOH = true;
break;
}
}
Как видно из комментария "// Search for EOH (CRLFCRLF)" хотели находить последовательность байт 0D,0A,0D,0A (CR == 0x0D, LF == 0x0A). Поскольку, байты располагаются в обратном порядке, константа для поиска равна 0x0A0D0A0D.
Видимо, это программа не очень успешно работает с иной последовательностью возвратов каретки и переносов строк. Это вызывает непонимание у автора, о чем говорит комментарий: " // VC-BUG?: '\r\n\r\n' results in 0x0A0D0A0D too, although it should not!". Так почему же алгоритм находит не только последовательность {0D,0A,0D,0A}, но и {0A,0D,0A,0D} ?
Всё очень просто. Алгоритм поиска движется в массиве по одному байту. Поэтому, если в программе встречается длинная последовательность вида {0A,0D,0A,0D,0A,0D,0A,...}, то алгоритм пропустит первый символ 0A и найдет дальше не то, что хотелось.
К сожалению при статическом анализе найти подобные дефекты невозможно.
Вот еще один пример странного кода :
TCHAR szCommand[_MAX_PATH * 2];
LPCTSTR lpsz = (LPCTSTR)GlobalLock(hData);
int commandLength = lstrlen(lpsz);
if (commandLength >= _countof(szCommand))
{
// The command would be truncated.
//This could be a security problem
TRACE(_T("Warning: ........\n"));
return 0;
}
// !!! MFC Bug Fix
_tcsncpy(szCommand, lpsz, _countof(szCommand) - 1);
szCommand[_countof(szCommand) - 1] = '\0';
// !!!
В данном случае "MFC Bug Fix" совершенно не соответсвует действительности, поскольку никакой ошибки в MFC здесь нет. Код не вызывает ошибок в таком виде, но возможно изначально было записано только: '_tcsncpy(szCommand, lpsz, _countof(szCommand) - 1);'. В таком случае ошибка действительно имела место быть. Но записать корректное копирование строк можно несколько короче:
_tcsncpy(szCommand, lpsz, _countof(szCommand));
Функции вида 'strncpy' сами добавляют завершающий нуль в конец строки, если строка источник не длиннее значения указанного в счетчике. А это именно так, так как выше есть соответствующая проверка. Случаи некорректного копирования строк в PVS-Studio уже успешно анализируются, поэтому ничего нового мы не узнали.
Заключение
Нами не было найдено ни одного нового шаблона ошибок для дальнейшего их включения в поиск статическим анализатором. Но все равно, это положительный опыт в исследовании альтернативных способов нахождения программных ошибок. И мы ещё некоторое время продолжим исследования комментариев в новых проектах, которые попадут в наши руки. Так же планируются некоторые усовершенствования утилиты поиска:
Возможно, такая программа может быть полезна, если вы получаете "в наследство" большой проект с многолетней историей кода и хотите посмотреть что же так не нравилось вашим предшественникам.