﻿# Что скрывают в себе комментарии

О пользе или вреде комментариев в коде программ много говорится и однозначного мнения так и не сформировалось\. Однако мы решили посмотреть на них с другой стороны\. Могут ли комментарии навести исследователя на скрытые ошибки в коде?

При изучении различных проектов на предмет ошибок, было замечено, что программисты иногда замечают дефекты, но не могут до конца разобраться в их причинах\. Нередко подозрение падает на компилятор\. Про этот эффект недавно писал мой коллега в статье "[Во всём виноват компилятор](https://pvs-studio.ru/ru/blog/posts/cpp/0161/)"\. В результате, программист делает в коде подпорку и оставляет различные комментарии\. Часто эти комментарии нецензурного характера\.

Мы решили, что это интересная сфера для исследований\. Просматривать файлы вручную или искать обычным поиском по одному слову это очень долгий и утомительный процесс\. Была написана утилита, которая ищет в "\.c" и "\.cpp" файлах подозрительные комментарии, основываясь на своем словаре "подозрительных слов"\. Например, в словарь подозрительных слов попали: fuck, bug, stupid, compiler\. 

Было получено очень большое количество строк с такими комментариями\. Поиск фрагментов действительно стоящих внимания, стал непростым и утомительным занятием\. Удалось найти мало интересного\. Намного меньше, чем хотелось\. 

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

Плохой результат, тоже результат\. Скорее всего,  мы сделаем вывод, что метод поиска странных комментариев тупиковый\. Он слишком трудоёмок и позволяет найти совсем немного ляпов\.

Но раз исследование проведено, мы решили поделиться парой примеров с вами\.

Например, такой пример кода:

```cpp
// 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 и найдет дальше не то, что хотелось\.

К сожалению при статическом анализе найти подобные дефекты невозможно\.

Вот еще один пример странного кода :

```cpp
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\);'\. В таком случае ошибка действительно имела место быть\. Но записать корректное копирование строк можно несколько короче: 

```cpp
_tcsncpy(szCommand, lpsz, _countof(szCommand));
```

Функции вида 'strncpy' сами добавляют завершающий нуль в конец строки, если строка источник не длиннее значения указанного в счетчике\. А это именно так, так как выше есть соответствующая проверка\. Случаи некорректного копирования строк в PVS\-Studio уже успешно анализируются, поэтому ничего нового мы не узнали\.

**Заключение**

Нами не было найдено ни одного нового шаблона ошибок для дальнейшего их включения в поиск статическим анализатором\. Но все равно, это положительный опыт в исследовании альтернативных способов нахождения программных ошибок\. И мы ещё некоторое время продолжим исследования комментариев в новых проектах, которые попадут в наши руки\. Так же планируются некоторые усовершенствования утилиты поиска: 

* написать простой синтаксический анализ для уменьшения нахождения "неинтересных"  строк;
* расширить словарь новыми выражениями\.

Возможно, такая программа может быть полезна, если вы получаете "в наследство" большой проект с многолетней историей кода и хотите посмотреть что же так не нравилось вашим предшественникам\.