SlideShare a Scribd company logo
Реклама PVS-Studio - статический анализ кода на языке Си и Си++                   file:///E:/PVS-Studio_detects_ru.html




          Реклама PVS-Studio - статический анализ
          кода на языке Си и Си++
          Авторы: Андрей Карпов, Евгений Рыжков

          Дата: 25.10.2011

               Аннотация
               Что такое статический анализ кода
               Инструмент PVS-Studio
               Типы выявляемых дефектов
               Работа с отчетом PVS-Studio
               Инкрементальный анализ кода
               Возврат инвестиций при использовании PVS-Studio (ROI)
               Поддержка наших пользователей
               Примеры выявленных ошибок в различных open-source проектах
                     Ошибки работы с массивами и строками
                     Неопределенное поведение (Undefined behavior)
                     Ошибки, связанные с приоритетом операций.
                     Ошибки форматированного вывода
                     Примеры выявленных опечаток в коде
                     Неверное использование базовых функций и классов
                     Примеры бессмысленного кода
                     Всегда ложные или истинные условия
                     Уязвимости в коде
                     Copy-Paste
                     Разное
               Заключение и вывод
               Различные ссылки

          Аннотация
          Этот документ рекламирует статический анализатор PVS-Studio. Описывается, как использование
          PVS-Studio уменьшит количество ошибок в коде проекта на языке C/C++/C++11 и сократит
          затраты на тестирование, отладку и сопровождение кода. Приводится большое количество
          примеров ошибок, найденных анализатором в различных Open-Source проектах. Документ
          описывает PVS-Studio на момент версии 4.38 от 12 октября 2011 и, как следствие, не отражает
          возможности следующих версий. Чтобы познакомиться с новыми возможностями, предлагаем
          посетить сайт продукта http://www.viva64.com или поискать обновленный вариант этой статьи.

          Что такое статический анализ кода
          Статический анализ кода - это методология выявления ошибок в программном обеспечении.
          Методология основана на быстром и эффективном просмотре программистом участков кода,
          помеченных статическим анализатором там, где потенциально может находиться ошибка.
          Другими словами инструмент для статического анализа определяет в тексте программы места,
          содержащие ошибки, предрасположенные к ошибкам или имеющие плохое форматирование.



Стр. 1 из 48                                                                                         28.10.2011 14:06
Реклама PVS-Studio - статический анализ кода на языке Си и Си++                     file:///E:/PVS-Studio_detects_ru.html


          Такие участки кода предоставляются программисту для изучения, и он может принять решение о
          модификации данного участка программы.

          Статический анализ кода отчасти схож с методикой обзоров кода (code review). Отличие в том, что
          роль экспертов здесь выполняет программное обеспечение. Конечно, возможности программы
          далеки от возможности команды людей. Но зато, программа неутомима, и её использование на
          несколько порядков дешевле по сравнению с обзорами кода.

          Статические анализаторы могут быть как общего назначения (например, PVS-Studio, Microsoft
          PREFast, Gimpel PC-Lint, Parasoft C++Test), так и специализированными для поиска определенных
          классов ошибок (например, Chord для верификации параллельных Java программ). Статические
          анализаторы обычно используются в компаниях с высокой культурой разработки и зрелыми
          процессами разработки программного обеспечения. Это связано с тем, что инструменты
          статического анализа требуют понимания принципов их работы, необходимости уделить
          некоторое время их изучению и интеграции в процесс разработки. Взамен они позволяют выявить
          большое количество ошибок на самых ранних этапах разработки программного кода.

          Основное преимущество использования статических анализаторов кода состоит в возможности
          существенного снижения стоимости устранения дефектов в программе. Чем раньше ошибка
          выявлена, тем меньше стоимость ее исправления. Так, согласно данным, приведенным в книге
          Макконнелла "Совершенный Код", исправление ошибки на этапе тестирования обойдется в десять
          раз дороже, чем на этапе конструирования (кодирования):




          Рисунок 1. Средняя стоимость исправления дефектов в зависимости от времени их внесения и
          обнаружения (данные для таблицы взяты из книги С. Макконнелла "Совершенный Код").

          Инструменты статического анализа позволяют выявить большое количество ошибок этапа
          конструирования, что существенно снижает стоимость разработки всего проекта.

          Инструмент PVS-Studio
          PVS-Studio это легкий в изучении и использовании инструмент статического анализа кода.
          PVS-Studio представляет собой модуль расширения к среде программирования Visual Studio
          2005/2008/2010. Впрочем, анализатор можно использовать и из командной строки, о чем более
          подробно можно узнать в документации.

          Основные характеристики PVS-Studio:



Стр. 2 из 48                                                                                           28.10.2011 14:06
Реклама PVS-Studio - статический анализ кода на языке Си и Си++                     file:///E:/PVS-Studio_detects_ru.html


          Поддерживаемые языки: С / C++ / С++11 (в тех рамках, в которых эти языки поддерживает
          компилятор Visual C++).

          Операционные системы: 32-битные и 64-битные версии Windows XP / 2003 / Vista / 2008 / 7.

          Системные требования: Системные требования к анализатору совпадают с требованиями к
          Microsoft Visual Studio.

          Режимы работы: Как расширение среды Visual Studio 2005/2008/2010. Запуск из командной строки
          (есть solution-файл / нет solution-файла). Примечание: работа PVS-Studio с Visual C++ Express
          Edition не возможна, поскольку эта система не поддерживает модули расширений.

          Интеграция с системами continuous integration: Есть.

          Сайт продукта: http://www.viva64.com/ru/

          Документация: На русском и английском языке.

          Возможность скачать демонстрационную версию: Есть.

          Возможность приобретения: Онлайн.

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

          Типы выявляемых дефектов
          Диагностические сообщения PVS-Studio можно разделить на 5 групп:

          1. Диагностика параллельных ошибок в OpenMP программах.

          Несмотря на то, что в 2006-2009 году компания Intel активно продвигала технологию OpenMP, она
          так и не нашла отклика в сердцах программистах и практически не используется. Мы решили
          оставить соответствующие диагностические правила, но далее не развивать это направление.
          Следовательно, на параллельных ошибках заострять внимание не будем и перейдем к более
          интересным возможностям анализатора. Интересующимся тематикой OpenMP предлагаем этот
          раздел сайта: http://www.viva64.com/ru/vivamp-tool/ .

          2. Диагностика 64-битных ошибок

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

               Коллекция примеров 64-битных ошибок в реальных программах: http://www.viva64.com
               /ru/a/0065/
               64-битный конь, который умеет считать: http://www.viva64.com/ru/a/0043/
               Что такое size_t и ptrdiff_t: http://www.viva64.com/ru/a/0050/
               Уроки разработки 64-битных приложений на языке Си/Си++: http://www.viva64.com/ru/l/


Стр. 3 из 48                                                                                           28.10.2011 14:06
Реклама PVS-Studio - статический анализ кода на языке Си и Си++                    file:///E:/PVS-Studio_detects_ru.html


          В перечисленных статьях подробно рассмотрена тематика 64-битных дефектов, и здесь мы не
          будем на ней останавливаться. Приведем только один пример, чтобы дать понять о каких ошибках
          в этих статьях идёт речь:

          dgCollisionCompoundBreakable::dgCollisionCompoundBreakable(...)
          {
            ...
            dgInt32 faceOffsetHitogram[256];
            dgSubMesh* mainSegmenst[256];
            ...
            memset (faceOffsetHitogram, 0, sizeof(faceOffsetHitogram));
            memset (mainSegmenst, 0, sizeof(faceOffsetHitogram));
            ...
          }

          Этот код был обнаружен PVS-Studio в проекте Newton Game Dynamics. Обратите внимание на
          второй вызов функции 'memset'. Из-за случайной опечатки эта функция заполняет нулями
          'sizeof(faceOffsetHitogram)' байт, а не 'sizeof(mainSegmenst)'.

          Почему эту ошибку мы называем 64-битной? Дело в том, что эта ошибка проявит себя только при
          компиляции кода в 64-битном режиме. В 32-битной программе размер указателей и типа 'dgInt32'
          совпадает. Это значит, что в 32-битной программе размер массивов faceOffsetHitogram и
          mainSegmenst совпадут. В 64-битной программе эти массивы занимают разное количество байт, а
          следовательно функция 'memset' заполнит только часть массива.

          3. Выявление неэффективных конструкций

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

          if ((strlen(directory) > 0) &&
              (directory[strlen(directory)-1] != ''))

          Анализатор выдаст для этого кода предупреждение V804. Этот код можно оптимизировать, если
          предварительно вычислить длину строки и поместить её во временную переменную. Это не всегда
          нужно. Однако, если подобный код выполняется множество раз в цикле, такая оптимизация может
          быть весьма полезна.

          4. Диагностические правила, имплементированные по заказу пользователей

          Эти правила достаточно специфичны и полезны только узкой группе пользователей. О них
          упомянуто, чтобы вы знали, что наша компания всегда готова откликнуться на любые пожелания
          наших клиентов!

          5. Диагностические правила общего назначения

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

          Лучшей рекламой для программистов являются примеры исходного кода. Поэтому не будем
          писать абстрактные тексты о возможностях статического анализа, а покажем эти самые примеры
          на практике. Если вы стремитесь поскорее посмотреть их, то перейдите к разделу "Примеры
          выявленных ошибок в различных open-source проектах". Или ещё немного потерпите и прочитайте
          всю скромную хвалебную статью по порядку.


Стр. 4 из 48                                                                                          28.10.2011 14:06
Реклама PVS-Studio - статический анализ кода на языке Си и Си++                     file:///E:/PVS-Studio_detects_ru.html



          Работа с отчетом PVS-Studio
          Если вы работаете с анализатором в рамках среды Visual Studio, то в вашем распоряжении будет
          простой интерфейс, состоящий из 2 компонент: новое меню и интерактивное окно для работы с
          предупреждениями.

          1. Меню PVS-Studio




          Рисунок 2. Меню PVS-Studio, интегрированное в Visual Studio 2005.

          С его помощью можно запустить анализ, сохранить/загрузить лог, изменить настройки и прочие
          функции, в которых любой программист сможет легко разобраться.

          2. Интегративное окно с предупреждениями




          Рисунок 3. Окно PVS-Studio для работы с предупреждениями (кликните на картинку для
          просмотра полноценного снимка экрана)

          Функциональность окна:

               Навигация по коду. Осуществляется двойным щелчком мыши по сообщению с помощью
               иконок вперёд/назад или с помощью горячих клавиш 'Alt - [' и 'Alt - ]'.


Стр. 5 из 48                                                                                           28.10.2011 14:06
Реклама PVS-Studio - статический анализ кода на языке Си и Си++                     file:///E:/PVS-Studio_detects_ru.html


               Открытие документации для соответствующей ошибки. Необходимо щелкнуть мышкой на
               коде ошибки.
               Включение/выключение различных наборов предупреждений. Например, можно
               просмотреть только предупреждения первого уровня важности, относящиеся к 64-битным
               диагностикам.
               Различные способы сортировки и фильтрации сообщений. Возможен поиск определенных
               сообщений. Есть и другие мелкие возможности, такие как "пометка звездочкой" сообщений,
               вызвавших интерес.
               Для отдельных сообщений также доступно контекстное меню (наведите на сообщение и
               нажмите правую кнопку мыши). Например, с помощью него можно осуществить такую
               важную функцию, как пометить диагностику как ложную (Mark selected errors as False
               Alarms).

          Инкрементальный анализ кода
          PVS-Studio позволяет дешево внедрить статический анализ в процесс разработки.

          Если включен режим "Incremental Analysis after Build", то анализатор запускается сразу после
          компиляции и проверяет только те файлы, которые были "задеты" правками пользователя. То есть
          пользователь видит ошибки только в том коде, который он непосредственно пишет или
          затрагивает при рефакторинге.

          Программисту не надо беспокоиться о большом объеме кода, с которым он в данный момент не
          работает. Возможно, этому коду уже более 5 лет. Он практически не модифицируется и
          большинство дефектов в нем уже исправлено. Этот код не надо бросаться проверять в первую
          очередь, и анализатор этого и не делает. Программист будет видеть предупреждения только в
          свежем коде. А уж если у него будет дополнительное время, он всегда сможет проверить проект
          целиком, заглянув в самые редко посещаемые места.

          Инкрементальный анализ выполняется в фоновом режиме, и вы можете, не дожидаясь его
          завершения, заниматься другими действиями и правкой кода. Если анализатор что-то найдет, то он
          просигнализирует это сменой цвета иконки окна и всплывающим уведомлением.




          Рисунок 5. Всплывающее уведомление PVS-Studio.

          Конечно, мы все не любим всякие назойливые всплывающие уведомления. Но в данном случае
          оно будет явно полезно программисту и будет появляться редко, при условии, что он не
          злоупотребляет ошибками в коде.

          Попробуйте. Мы уверены, программистам понравится этот режим работы.




Стр. 6 из 48                                                                                           28.10.2011 14:06
Реклама PVS-Studio - статический анализ кода на языке Си и Си++                      file:///E:/PVS-Studio_detects_ru.html



          Возврат инвестиций при использовании PVS-Studio (ROI)
          Этот раздел на тот случай, если попробуете анализатор PVS-Studio и найдете только несколько
          ошибок. У вас возникнет вопрос, в чём польза от использования статического анализа, если он
          смог выявить только небольшое количество дефектов? Если это произошло, то вспомните про этот
          текст и ознакомьтесь со следующими 2 заметками:

               Лев Толстой и статический анализ кода: http://www.viva64.com/ru/b/0105/
               Статический анализ и ROI: http://www.viva64.com/ru/b/0100/

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

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

               создание файлов-отчетов в определенном формате;
               разработка скриптов (сценариев) для особых вариантов запуска PVS-Studio;
               доработка инструмента для взаимодействия с той или иной системой непрерывной
               интеграции или сборки;
               введение новых настроек в инструменте;
               проверка не всех файлов проекта/решения, а только некоторых (по именам или по времени
               модификации – к примеру, за последний день).

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

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

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

          Из проверенных нами проектов, конечно, взято только по несколько ошибок. Если описывать все



Стр. 7 из 48                                                                                            28.10.2011 14:06
Реклама PVS-Studio - статический анализ кода на языке Си и Си++                        file:///E:/PVS-Studio_detects_ru.html


          найденные дефекты, то это уже будет справочник. Список проверенных проектов:

               Apache HTTP Server - http://httpd.apache.org/
               Audacity - http://audacity.sourceforge.net/
               Chromium - http://www.chromium.org/
               Clang - http://clang-analyzer.llvm.org/
               CMake - http://www.cmake.org/
               Crystal Space 3D SDK - http://www.crystalspace3d.org/main/Main_Page
               Emule - http://www.emule.com/
               FAR Manager - http://www.farmanager.com/
               FCE Ultra - http://fceux.com/web/home.html
               Fennec Media Project - http://fennec.sourceforge.net/
               G3D Content Pak - http://sourceforge.net/projects/g3d-cpp/
               IPP Samples - http://www.viva64.com/go.php?url=449
               Lugaru - http://www.wolfire.com/lugaru
               Miranda IM - http://www.miranda-im.org/
               MySQL - http://www.mysql.com/
               Newton Game Dynamics - http://newtondynamics.com/forum/newton.php
               Notepad++ - http://notepad-plus-plus.org/
               Pixie - http://www.renderpixie.com/
               PNG library - http://libpng.org/pub/png/
               QT - http://qt.nokia.com/products/
               ReactOS - http://www.reactos.org/en/
               Shareaza - http://www.shareaza.com/
               SMTP Client with SSL/TLS - http://www.codeproject.com/KB/IP/smtp_ssl.aspx
               StrongDC++ - http://strongdc.sourceforge.net/index.php?lang=eng
               Swiss-Army Knife of Trace - http://www.codeproject.com/KB/trace/tracetool.aspx
               TortoiseSVN - http://tortoisesvn.net/
               Ultimate TCP/IP - http://www.codeproject.com/KB/MFC/UltimateTCPIP.aspx
               VirtualDub - http://www.virtualdub.org/
               WinDjView - http://windjview.sourceforge.net/
               WinMerge - http://winmerge.org/
               Wolfenstein 3D - http://en.wikipedia.org/wiki/Wolfenstein_3D
               И некоторые другие.




Стр. 8 из 48                                                                                              28.10.2011 14:06
Реклама PVS-Studio - статический анализ кода на языке Си и Си++                  file:///E:/PVS-Studio_detects_ru.html




          Рисунок 6. Логотипы проверенных проектов

          Ошибки работы с массивами и строками

          Ошибки в обработке массивов и строк являются самым обширным классом дефектов в
          программах на языке Си/Си++. Это плата за возможность эффективной низкоуровневой работы с
          оперативной памятью. В статье будет показа лишь малая часть подобных ошибок, найденных
          анализатором PVS-Studio. Но думаем, что любой Си/Си++ программист понимает, как их много и
          как они коварны.

          Пример 1. Проект Wolfenstein 3D. Очистка только части объекта.

          void CG_RegisterItemVisuals( int itemNum ) {
            ...
            itemInfo_t *itemInfo;
            ...
            memset( itemInfo, 0, sizeof( &itemInfo ) );


Стр. 9 из 48                                                                                        28.10.2011 14:06
Реклама PVS-Studio - статический анализ кода на языке Си и Си++                        file:///E:/PVS-Studio_detects_ru.html


             ...
         }

         Ошибка найдена с помощью диагностики V568: It's odd that the argument of sizeof() operator is the
         '&itemInfo' expression. cgame cg_weapons.c 1467.

         Оператор sizeof() вычисляет размер указателя, а не структуры 'itemInfo_t'. На самом деле должно
         быть написано "sizeof(*itemInfo)".

         Пример 2. Проект Wolfenstein 3D. Копирование только части матрицы.

         ID_INLINE mat3_t::mat3_t( float src[ 3 ][ 3 ] ) {
           memcpy( mat, src, sizeof( src ) );
         }

         Ошибка найдена с помощью диагностики V511: The sizeof() operator returns size of the pointer, and
         not of the array, in 'sizeof(src)' expression. Splines math_matrix.h 94

         Как правило, программисты ожидают, что 'sizeof(src)' вернет размер массива равного
         "3*3*sizeof(float)". Но согласно стандарту языка, 'src' это просто указатель, а вовсе не массив.
         Таким образом, матрица будет скопирована только частично. Функция 'memcpy' скопирует 4 или 8
         байт (размер указателя) в зависимости от того, этот код 32-битный или 64-битный.

         Если хочется скопировать матрицу целиком, то можно передать в функцию ссылку на массив.
         Корректный вариант кода:

         ID_INLINE mat3_t::mat3_t( float (&src)[3][3] )
         {
           memcpy( mat, src, sizeof( src ) );
         }

         Пример 3. Проект FAR Manager. Очистка только части массива.

         struct TreeItem
         {
           int *Last;
           size_t LastCount;
           ...
           void Clear()
           {
             strName.Clear();
             memset(Last, 0, sizeof(Last));
             Depth=0;
           }
         };

         Ошибка найдена с помощью диагностики V579: The memset function receives the pointer and its size
         as arguments. It is possibly a mistake. Inspect the third argument. far treelist.hpp 66

         Скорее всего, здесь не хватает умножения на количество очищаемых элементов, и код должен был
         выглядеть так: "memset(Last, 0, LastCount * sizeof(Last));".

         Пример 4. Проект ReactOS. Некорректное вычисление длины строки.

         static const PCHAR Nv11Board = "NV11 (GeForce2) Board";
         static const PCHAR Nv11Chip = "Chip Rev B2";
         static const PCHAR Nv11Vendor = "NVidia Corporation";

         BOOLEAN
         IsVesaBiosOk(...)



Стр. 10 из 48                                                                                             28.10.2011 14:06
Реклама PVS-Studio - статический анализ кода на языке Си и Си++                       file:///E:/PVS-Studio_detects_ru.html


         {
             ...
             if (!(strncmp(Vendor, Nv11Vendor, sizeof(Nv11Vendor))) &&
                 !(strncmp(Product, Nv11Board, sizeof(Nv11Board))) &&
                 !(strncmp(Revision, Nv11Chip, sizeof(Nv11Chip))) &&
                 (OemRevision == 0x311))
             ...
         }

         Ошибка найдена с помощью диагностики V579: The strncmp function receives the pointer and its size
         as arguments. It is possibly a mistake. Inspect the third argument. vga vbe.c 57

         Имеющиеся в коде вызовы функции 'strncmp' сравнивают только несколько первых символов, а не
         строки целиком. Ошибка в том, что для вычисления длины строк используется совершенно
         неуместный здесь оператор sizeof(). Оператор sizeof() вычисляет размер указателя, а вовсе не
         количество байт в строке.

         Самое неприятное и коварное с этой ошибкой в том, что этот код почти работает. В 99% случаев
         сравнение по первым нескольким символам бывает достаточно. Зато 1% может подарить массу
         удовольствий и долгую отладку.

         Пример 5. Проект VirtualDub. Выход за рамки массива (явный индекс).

         struct ConvoluteFilterData {
          long m[9];
          long bias;
          void *dyna_func;
          DWORD dyna_size;
          DWORD dyna_old_protect;
          BOOL fClip;
         };

         static unsigned long __fastcall do_conv(
           unsigned long *data,
           const ConvoluteFilterData *cfd,
           long sflags, long pit)
         {
           long rt0=cfd->m[9], gt0=cfd->m[9], bt0=cfd->m[9];
           ...
         }

         Ошибка найдена с помощью диагностики V557: Array overrun is possible. The '9' index is pointing
         beyond array bound. VirtualDub f_convolute.cpp 73

         Одна из самых простых ошибок, приводящих к выходу за границы массива. Явно используется
         индекс 9, хотя индекс последнего элемента равен 8. Возможно, автор на мгновение забыл, что в
         Си/Си++ элементы массивов нумеруются с нуля, а не с единицы. Такое случается, когда
         приходится переключаться между различными языками программирования.

         Пример 6. Проект CPU Identifying Tool. Выход за рамки массива (индекс в макросе).

         #define FINDBUFFLEN 64 // Max buffer find/replace size
         ...
         int WINAPI Sticky (...)
         {
           ...
           static char findWhat[FINDBUFFLEN] = {'0'};
           ...
           findWhat[FINDBUFFLEN] = '0';
           ...
         }



Стр. 11 из 48                                                                                            28.10.2011 14:06
Реклама PVS-Studio - статический анализ кода на языке Си и Си++                       file:///E:/PVS-Studio_detects_ru.html


         Ошибка найдена с помощью диагностики V557: Array overrun is possible. The '64' index is pointing
         beyond array bound. stickies stickies.cpp 7947

         Эта ошибочная ситуация является разновидностью предыдущей. Терминальный ноль
         записывается за границей массива. Корректным вариантом кода будет: "findWhat[FINDBUFFLEN -
         1] = '0';".

         Пример 7. Проект Wolfenstein 3D. Выход за рамки массива (неверное выражение).

         void BotTeamAI( bot_state_t *bs ) {
           ...
           bs->teamleader[sizeof( bs->teamleader )] = '0';
           ...
         }

         Ошибка найдена с помощью диагностики V557: Array overrun is possible. The 'sizeof
         (bs->teamleader)' index is pointing beyond array bound. game ai_team.c 548

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

         Терминальный ноль записывается за пределами массива 'teamleader'. Корректный вариант:

         bs->teamleader[sizeof( bs->teamleader ) - 1] = '0';

         Пример 8. Проект Miranda IM. Копирование только части строки.

         typedef struct _textrangew
         {
           CHARRANGE chrg;
           LPWSTR lpstrText;
         } TEXTRANGEW;

         const wchar_t* Utils::extractURLFromRichEdit(...)
         {
           ...
           ::CopyMemory(tr.lpstrText, L"mailto:", 7);
           ...
         }

         Ошибка найдена с помощью диагностики V512: A call of the 'memcpy' function will lead to a buffer
         overflow or underflow. tabsrmm utils.cpp 1080

         Если используются Unicode-строки, то один символ занимает не один байт, а 2 или 4 байта (в
         зависимости от используемой модели данных в компиляторе). К сожалению, про этом легко
         забывается, и нередко в программах можно встретить дефекты, аналогичные тому, который
         показан здесь.

         Функция 'CopyMemory' скопирует только часть строки L"mailto:", так как работает с байтами, а не
         с символами. Код можно исправить, используя более подходящую функцию для копирования
         строк или, по крайней мере, умножив число 7 на sizeof(wchar_t).

         Пример 9. Проект CMake. Выход за границу массива внутри цикла.

         static const struct {
           DWORD   winerr;
           int     doserr;
         } doserrors[] =



Стр. 12 из 48                                                                                            28.10.2011 14:06
Реклама PVS-Studio - статический анализ кода на языке Си и Си++                       file:///E:/PVS-Studio_detects_ru.html


         {
           ...
         };

         static void
         la_dosmaperr(unsigned long e)
         {
           ...
           for (i = 0; i < sizeof(doserrors); i++)
           {
             if (doserrors[i].winerr == e)
             {
               errno = doserrors[i].doserr;
               return;
             }
           }
           ...
         }

         Ошибка найдена с помощью диагностики V557: Array overrun is possible. The value of 'i' index could
         reach 367. cmlibarchive archive_windows.c 1140, 1142

         Обработчик ошибок сам содержит ошибку. Оператор sizeof() возвращает размер массива в байтах,
         а не количество элементов в нём. В результате, в цикле программа попытается перебирать намного
         больше элементов, чем должна. Корректный цикл должен выглядеть так:

         for (i = 0; i < sizeof(doserrors) / sizeof(*doserrors); i++)

         Пример 10. Проект CPU Identifying Tool. Печать строки саму в себя.

         char * OSDetection ()
         {
           ...
           sprintf(szOperatingSystem,
                   "%sversion %d.%d %s (Build %d)",
                   szOperatingSystem,
                   osvi.dwMajorVersion,
                   osvi.dwMinorVersion,
                   osvi.szCSDVersion,
                   osvi.dwBuildNumber & 0xFFFF);
           ...
           sprintf (szOperatingSystem, "%s%s(Build %d)",
                    szOperatingSystem, osvi.szCSDVersion,
                    osvi.dwBuildNumber & 0xFFFF);
           ...
         }

         Ошибка найдена с помощью диагностики V541: It is dangerous to print the string 'szOperatingSystem'
         into itself. stickies camel.cpp 572, 603

         К достаточно печальным последствиям может привести попытка форматированной печати строки
         в саму себя. Результат работы такого кода зависит от входных данных и предсказать, что
         произойдет сложно. Скорее всего, результатом работы станет бессмысленная строка или
         возникнет Access Violation.

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

         Пример 11. Проект FCE Ultra. Для строки выделяется памяти меньше, чем надо.



Стр. 13 из 48                                                                                            28.10.2011 14:06
Реклама PVS-Studio - статический анализ кода на языке Си и Си++                                file:///E:/PVS-Studio_detects_ru.html


         int FCEUI_SetCheat(...)
         {
           ...
           if((t=(char *)realloc(next->name,strlen(name+1))))
           ...
         }

         Ошибка найдена с помощью диагностики V518: The 'realloc' function allocates strange amount of
         memory calculated by 'strlen(expr)'. Perhaps the correct variant is 'strlen(expr) + 1'. fceux cheat.cpp 609

         Причиной ошибки является опечатка. Аргументом функции strlen() должен быть указатель 'name',
         а вовсе не выражение "name+1". В результате, функция realloc выделит на 2 байта меньше памяти,
         чем необходимо. Один байт потеряется из-за того, что к длине строки не прибавлена единица.
         Другой байт потеряется из-за того, что функция 'strlen' считает длину строки, пропустив первый
         символ.

         Пример 12. Проект Notepad++. Частичное обнуление массива.

         #define CONT_MAP_MAX 50
         int _iContMap[CONT_MAP_MAX];
         ...
         DockingManager::DockingManager()
         {
           ...
           memset(_iContMap, -1, CONT_MAP_MAX);
           ...
         }

         Ошибка найдена с помощью диагностики V512: A call of the memset function will lead to a buffer
         overflow or underflow. notepadPlus DockingManager.cpp 60

         Очередная путаница с количеством элементов в массиве и его размером. Забыто умножение на
         sizeof(int).

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

         Неопределенное поведение (Undefined behavior)

         В начале немного теории.

         Неопределённое поведение (англ. undefined behaviour) — свойство некоторых языков
         программирования (наиболее заметно в Cи и Си++) в определённых ситуациях выдавать
         результат, зависящий от реализации компилятора. Другими словами, спецификация не определяет
         поведение языка в любых возможных ситуациях, а говорит: "при условии А результат операции Б
         не определён". Допускать такую ситуацию в программе считается ошибкой, даже если на
         некотором компиляторе программа успешно выполняется, она не будет кроссплатформенной и
         может отказать на другой машине в другой ОС и даже на других настройках компилятора.

         Точка следования (англ. Sequence point) — в программировании любая точка программы, в
         которой гарантируется, что все побочные эффекты предыдущих вычислений уже проявились, а
         побочные эффекты последующих еще отсутствуют. Подробнее про точки следования и какие
         ситуации неопределенного поведения с ними связаны можно прочитать здесь:
         http://www.viva64.com/ru/t/0065/.




Стр. 14 из 48                                                                                                     28.10.2011 14:06
Реклама PVS-Studio - статический анализ кода на языке Си и Си++                       file:///E:/PVS-Studio_detects_ru.html


         Пример 1. Проект Chromium. Некорректное использование умного указателя.

         void AccessibleContainsAccessible(...)
         {
           ...
           auto_ptr<VARIANT> child_array(new VARIANT[child_count]);
           ...
         }

         Ошибка найдена с помощью диагностики V554: Incorrect use of auto_ptr. The memory allocated with
         'new []' will be cleaned using 'delete'. interactive_ui_tests accessibility_win_browsertest.cc 171

         Это пример демонстрирует, когда использование умного указателя может привести к
         неопределенному поведению. Проявить себя это может повреждением кучи, аварийным
         завершением программы, неполному разрушению объектов или любым другим образом. Ошибка
         заключается в том, что память выделяется с помощью оператора new [], а освобождается в
         деструкторе класса 'auto_ptr' с помощью оператора delete:

         ~auto_ptr() {
           delete _Myptr;
         }

         Чтобы исправить ситуации, необходимо использовать более подходящий класс, например
         boost::scoped_array.

         Пример 2. Проект IPP Samples. Классический Undefined behavior.

         template<typename T, Ipp32s size> void HadamardFwdFast(...)
         {
           Ipp32s *pTemp;
           ...
           for(j=0;j<4;j++) {
             a[0] = pTemp[0*4] + pTemp[1*4];
             a[1] = pTemp[0*4] - pTemp[1*4];
             a[2] = pTemp[2*4] + pTemp[3*4];
             a[3] = pTemp[2*4] - pTemp[3*4];
             pTemp = pTemp++;
             ...
           }
           ...
         }

         Ошибка найдена с помощью диагностики V567: Undefined behavior. The 'pTemp' variable is
         modified while being used twice between sequence points. me umc_me_cost_func.h 168

         Это классический пример неопределенного поведения программы. Именно такую конструкцию
         используют для демонстрации Undefined behavior во многих статьях. Неизвестно, увеличится
         pTemp на единицу или нет. Два действия по изменению значения pTemp находятся в одной точке
         следования. Это значит, что компилятор может создать следующий псевдокод:

         pTemp = pTemp + 1;

         pTemp = pTemp;

         А может, создать другой вариант кода:

         TMP = pTemp;

         pTemp = pTemp + 1;


Стр. 15 из 48                                                                                            28.10.2011 14:06
Реклама PVS-Studio - статический анализ кода на языке Си и Си++                           file:///E:/PVS-Studio_detects_ru.html


         pTemp = TMP;

         Какой именно код будет создан, зависит от компилятора и ключей оптимизации.

         Пример 3. Проект Fennec Media Project. Сложное выражение.

         uint32 CUnBitArrayOld::DecodeValueRiceUnsigned(uint32 k)
         {
           ...
           while (!(m_pBitArray[m_nCurrentBitIndex >> 5] &
             Powers_of_Two_Reversed[m_nCurrentBitIndex++ & 31])) {}
           ...
         }

         Ошибка найдена с помощью диагностики V567: Undefined behavior. The 'm_nCurrentBitIndex'
         variable is modified while being used twice at single sequence point. MACLib unbitarrayold.cpp 78

         Между двумя использованиями переменной m_nCurrentBitIndex нет точек следования. Это значит,
         что стандартом не определено, в какой момент эта переменная увеличится. Соответственно, в
         зависимости от компилятора и ключей оптимизации, этот код может работать по-разному.

         Пример 4. Проект Miranda IM. Сложное выражение.

         short ezxml_internal_dtd(ezxml_root_t root,
           char *s, size_t len)
         {
           ...
           while (*(n = ++s + strspn(s, EZXML_WS)) && *n != '>') {
           ...
         }

         Ошибка найдена с помощью диагностики V567: Undefined behavior. The 's' variable is modified
         while being used twice between sequence points.msne zxml.c 371

         Здесь используется префиксный инкремент переменной. Но это ничего не значит. Нет никакой
         гарантии, что переменная 's' будет увеличена перед вызовом функции strspn().

         Ошибки, связанные с приоритетом операций.

         Для легкости понимания примеров освежим в памяти таблицу приоритетов операций.




Стр. 16 из 48                                                                                                28.10.2011 14:06
Реклама PVS-Studio - статический анализ кода на языке Си и Си++                          file:///E:/PVS-Studio_detects_ru.html




         Рисунок 7 - Приоритет операций языка Си/Си++

         Пример 1. Проект MySQL. Приоритет операции ! и &.

         int ha_innobase::create(...)
         {
           ...
           if (srv_file_per_table
               && !mysqld_embedded
               && (!create_info->options & HA_LEX_CREATE_TMP_TABLE)) {
           ...
         }

         Ошибка найдена с помощью диагностики V564: The '&' operator is applied to bool type value. You've
         probably forgotten to include parentheses or intended to use the '&&' operator. innobase ha_innodb.cc
         6789


Стр. 17 из 48                                                                                               28.10.2011 14:06
Реклама PVS-Studio - статический анализ кода на языке Си и Си++                             file:///E:/PVS-Studio_detects_ru.html


         По замыслу программиста, часть выражения должна проверить, что определенный бит в
         переменной 'create_info->options' равен нулю. Однако, приоритет операции '!' выше, чем операции
         '&'. И выражение работает так:

         ((!create_info->options) & HA_LEX_CREATE_TMP_TABLE)
         Чтобы код работал правильно, необходимо использовать дополнительные скобки:
         (!(create_info->options & HA_LEX_CREATE_TMP_TABLE))

         Или, что на наш взгляд более красиво, написать так:

         ((create_info->options & HA_LEX_CREATE_TMP_TABLE) == 0)

         Пример 2. Проект Emule. Приоритет операции * и ++.

         STDMETHODIMP
         CCustomAutoComplete::Next(..., ULONG *pceltFetched)
         {
           ...
           if (pceltFetched != NULL)
             *pceltFetched++;
           ...
         }

         Ошибка найдена с помощью диагностики V532: Consider inspecting the statement of '*pointer++'
         pattern. Probably meant: '(*pointer)++'. emule customautocomplete.cpp 277

         Если указатель 'pceltFetched' не нулевой, функция должна увеличивать переменную типа ULONG,
         на которую этот указатель указывает. Ошибка в том, что в приоритет операции '++' выше, чем
         приоритет операции '*' (разыменования указателя). Строка "*pceltFetched++;" эквивалентна
         следующим действиям:

         TMP = pceltFetched + 1;
         *pceltFetched;
         pceltFetched = TMP;

         Фактически, здесь просто увеличивается значение указателя. Чтобы код стал корректен,
         необходимо добавить скобки: "(*pceltFetched)++;".

         Пример 3. Проект Chromium. Приоритет операции & и !=.

         #define FILE_ATTRIBUTE_DIRECTORY 0x00000010

         bool GetPlatformFileInfo(PlatformFile file, PlatformFileInfo* info) {
           ...
           info->is_directory =
             file_info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY != 0;
           ...
         }

         Ошибка найдена с помощью диагностики V564: The '&' operator is applied to bool type value. You've
         probably forgotten to include parentheses or intended to use the '&&' operator. base platform_file_win.cc
         216

         Очень легко забыть, что приоритет операции '!=' выше, чем операции '&'. Так произошло и здесь.
         В результате получается выражение:

         info->is_directory =
           file_info.dwFileAttributes & (0x00000010 != 0);

         Упростим выражение:


Стр. 18 из 48                                                                                                  28.10.2011 14:06
Реклама PVS-Studio - статический анализ кода на языке Си и Си++                         file:///E:/PVS-Studio_detects_ru.html


         info->is_directory = file_info.dwFileAttributes & (true);

         Ещё раз упростим выражение:

         info->is_directory = file_info.dwFileAttributes & 1;

         Получается, что вместо пятого бита, протестировали первый бит. Чтобы исправить ситуацию,
         требуются вставить дополнительные скобки.

         Пример 4. Проект BCmenu. Путаница с IF и ELSE.

         void BCMenu::InsertSpaces(void)
         {
           if(IsLunaMenuStyle())
             if(!xp_space_accelerators) return;
           else
             if(!original_space_accelerators) return;
           ...
         }

         Ошибка найдена с помощью диагностики V563: It is possible that this 'else' branch must apply to the
         previous 'if' statement. fire bcmenu.cpp 1853

         Здесь ошибка не с приоритетом операций, но родственная ей. Не учтено, что ветка 'else' относится
         к ближайшему оператору 'if'. Видно, что код оформлен исходя из того, как будто он работает так:

         if(IsLunaMenuStyle()) {
           if(!xp_space_accelerators) return;
         } else {
           if(!original_space_accelerators) return;
         }

         Но на самом деле он эквивалентен следующей конструкции:

         if(IsLunaMenuStyle())
         {
            if(!xp_space_accelerators) {
              return;
            } else {
              if(!original_space_accelerators) return;
            }
         }

         Пример 5. Проект IPP Samples. Приоритет операции ?: и |.

         vm_file* vm_file_fopen(...)
         {
           ...
           mds[3] = FILE_ATTRIBUTE_NORMAL |
                    (islog == 0) ? 0 : FILE_FLAG_NO_BUFFERING;
           ...
         }

         Ошибка найдена с помощью диагностики V502: Perhaps the '?:' operator works in a different way than
         it was expected. The '?:' operator has a lower priority than the '|' operator. vm vm_file_win.c 393

         В зависимости от значения переменной 'islog', выражение должно было быть равно
         "FILE_ATTRIBUTE_NORMAL" или "FILE_ATTRIBUTE_NORMAL |
         FILE_FLAG_NO_BUFFERING". Но этого не происходит. Приоритет операции '?:' ниже, чем
         операции '|'. В результате код работает так:



Стр. 19 из 48                                                                                              28.10.2011 14:06
Реклама PVS-Studio - статический анализ кода на языке Си и Си++                             file:///E:/PVS-Studio_detects_ru.html


         mds[3] = (FILE_ATTRIBUTE_NORMAL | (islog == 0)) ?
           0 : FILE_FLAG_NO_BUFFERING;

         Упростим выражение:

         mds[3] = (0x00000080 | ...) ? 0 : FILE_FLAG_NO_BUFFERING;

         Так как FILE_ATTRIBUTE_NORMAL равняется 0x00000080, то условие всегда истинно. Это
         означает, что в mds[3] всегда будет записываться 0.

         Пример 6. Проект Newton Game Dynamics. Приоритет операции ?: и *.

         dgInt32 CalculateConvexShapeIntersection (...)
         {
           ...
           den = dgFloat32 (1.0e-24f) *
                 (den > dgFloat32 (0.0f)) ?
                   dgFloat32 (1.0f) : dgFloat32 (-1.0f);
           ...
         }

         Ошибка найдена с помощью диагностики V502: Perhaps the '?:' operator works in a different way than
         it was expected. The '?:' operator has a lower priority than the '*' operator. physics dgminkowskiconv.cpp
         1061

         В этом коде ошибка вновь связана с низким приоритетом операции '?:'. Условием для оператора '?:'
         является бессмысленное подвыражение "dgFloat32 (1.0e-24f) * (den > dgFloat32 (0.0f))". Исправить
         ситуацию можно, используя круглые скобки.

         Кстати, программисты часто забывают о коварстве оператора '?:'. Предлагаю заметку на эту тему:
         "Как уменьшить вероятность ошибки на этапе написания кода. Заметка N2".

         Ошибки форматированного вывода

         Примеры этих ошибок однообразны и скучны, поэтому рассмотрим совсем немного примеров. Их
         суть в том, что функции с переменным количеством аргументов принимают фактические
         аргументы, несовместимые со строкой, задающей формат. Любой программист, использующий
         такие функции, как printf(), хорошо знаком с данной разновидностью ошибок.

         Пример 1. Проект ReactOS. Некорректная печать символа типа WCHAR.

         static void REGPROC_unescape_string(WCHAR* str)
         {
           ...
           default:
             fprintf(stderr,
               "Warning! Unrecognized escape sequence: %c'n",
               str[str_idx]);
           ...
         }

         Ошибка найдена с помощью диагностики V576: Incorrect format. Consider checking the third actual
         argument of the 'fprintf' function. The char type argument is expected. regedit regproc.c 293

         Функция fprinf() должна распечатать символ типа char. Но третьим аргументов является символ
         типа WCHAR. Пользователю будет выдано некорректно сформированное сообщение. Чтобы код
         стал корректен, в строке, задающей формат, следует заменить '%c' на '%C'.



Стр. 20 из 48                                                                                                  28.10.2011 14:06
Реклама PVS-Studio - статический анализ кода на языке Си и Си++                            file:///E:/PVS-Studio_detects_ru.html


         Пример 2. Проект Intel AMT SDK. Пропущенный символ '%'.

         void addAttribute(...)
         {
           ...
           int index = _snprintf(temp, 1023,
             "%02x%02x:%02x%02x:%02x%02x:%02x%02x:"
             "%02x%02x:02x%02x:%02x%02x:%02x%02x",
             value[0],value[1],value[2],value[3],value[4],
             value[5],value[6],value[7],value[8],
             value[9],value[10],value[11],value[12],
             value[13],value[14],value[15]);
           ...
         }

         Ошибка найдена с помощью диагностики V576: Incorrect format. A different number of actual
         arguments is expected while calling '_snprintf' function. Expected: 18. Present: 19. mod_pvs
         mod_pvs.cpp 308

         На взгляд найти здесь ошибку очень непросто. Однако, статический анализатор PVS-Studio
         неутомим и замечает, что функция принимает больше фактических аргументов, чем задано в
         строке форматирования. Дело в том, что в одном месте пропущен символ '%'. Выделим этот
         фрагмент:

         "%02x%02x:[HERE]02x%02x:%02x%02x:%02x%02x",

         Пример 3. Проект Intel AMT SDK. Неиспользуемый аргумент.

         bool GetUserValues(...)
         {
           ...
           printf("Error: illegal value. Aborting.n", tmp);
           return false;
         }

         Ошибка найдена с помощью диагностики V576: Incorrect format. A different number of actual
         arguments is expected while calling 'printf' function. Expected: 1. Present: 2. RemoteControlSample
         remotecontrolsample.cpp 792

         Ошибка в том, что переменная 'tmp' никак не используется при выводе информационного
         сообщения.

         Пример 4. Проект G3D Content Pak. Печать бессмысленных данных.

         class Matrix3 {
           ...
           inline float* operator[] (int iRow) {
           ...
         };
         void AnyVal::serialize(G3D::TextOutput& t) const {
           ...
           const Matrix3& m = *(Matrix3*)m_value;
           ...
           t.printf("%10.5f, %10.5f, %10.5f,n
                    %10.5f, %10.5f, %10.5f,n
                    %10.5f, %10.5f, %10.5f)",
                    m[0, 0], m[0, 1], m[0, 2],
                    m[1, 0], m[1, 1], m[1, 2],
                    m[2, 0], m[2, 1], m[2, 2]);
           ...
         }



Стр. 21 из 48                                                                                                  28.10.2011 14:06
Реклама PVS-Studio - статический анализ кода на языке Си и Си++                      file:///E:/PVS-Studio_detects_ru.html


         Ошибка найдена с помощью диагностики V520: The comma operator ',' in array index expression '[0,
         0]'. graphics3D anyval.cpp 275

         Программа вместо матрицы распечатает бессмысленные значения. Такой код можно написать,
         если работать с разными языками программирования и забыть на время, как получать доступ к
         элементу двухмерного массива в языке Си.

         Рассмотрим, как работает выражение 'm[0, 1]'. Вначале вычисляется выражение "0, 1". Результатом
         такого выражения является 1. Затем вызывается функция 'operator[]' в классе Matrix3. Функция
         принимает фактический аргумент 1 и вернет указатель на первую строку в матрице. Именно
         значение этого указателя и будет распечатано функцией 'printf()', хотя она ожидает значение типа
         float.

         Корректный вариант:

         t.printf("%10.5f, %10.5f, %10.5f,n
                  %10.5f, %10.5f, %10.5f,n
                  %10.5f, %10.5f, %10.5f)",
                  m[0][0], m[0][1], m[0][2],
                  m[1][0], m[1][1], m[1][2],
                  m[2][0], m[2][1], m[2][2]);


         Примеры выявленных опечаток в коде

         Огромное количество ошибок при программировании допускается из-за опечаток. Большинство
         этих ошибок быстро выявляются на самых ранних этапах тестирования. Однако, некоторые такие
         ошибки надолго остаются в коде программы, доставляя беспокойство программистам и
         неудобства пользователям.

         Количество таких ошибок можно существенно сократить, используя статический анализатор
         PVS-Studio. Анализатор найдет их еще до начала тестирования, что существенно сократит цену
         нахождения и устранения дефектов.

         Пример 1. Проект Miranda IM. Присваивание внутри IF.

         void CIcqProto::handleUserOffline(BYTE *buf, WORD wLen)
         {
           ...
           else if (wTLVType = 0x29 && wTLVLen == sizeof(DWORD))
           ...
         }

         Ошибка найдена с помощью диагностики V560: A part of conditional expression is always true: 0x29.
         icqoscar8 fam_03buddy.cpp 632

         Из-за опечатки, внутри условия оператора 'if' происходит присваивание. Корректное условие: "if
         (wTLVType == 0x29 && wTLVLen == sizeof(DWORD))".

         Пример 2. Проект ReactOS. Ошибка присваивания.

         BOOL WINAPI GetMenuItemInfoA(...)
         {
           ...
           mii->cch = mii->cch;
           ...
         }




Стр. 22 из 48                                                                                           28.10.2011 14:06
Реклама PVS-Studio - статический анализ кода на языке Си и Си++                         file:///E:/PVS-Studio_detects_ru.html


         Ошибка найдена с помощью диагностики V570: The 'mii->cch' variable is assigned to itself. user32
         menu.c 4347

         Значение переменной присваивается само себе. Очевидно, планировалось написать так: "mii->cch
         = miiW->cch;".

         Пример 3. Проект Clang. Опечатка в названии объекта.

         static Value *SimplifyICmpInst(...) {
           ...
           case Instruction::Shl: {
             bool NUW =
               LBO->hasNoUnsignedWrap() && LBO->hasNoUnsignedWrap();
             bool NSW =
               LBO->hasNoSignedWrap() && RBO->hasNoSignedWrap();
           ...
         }

         Ошибка найдена с помощью диагностики V501: There are identical sub-expressions
         'LBO->hasNoUnsignedWrap ()' to the left and to the right of the '&&' operator. LLVMAnalysis
         instructionsimplify.cpp 1891

         Имеется опечатка при использовании переменных с похожими именами. В первой строке надо
         использовать как переменную LBO, так и RBO. Исправленный вариант кода:

         bool NUW = LBO->hasNoUnsignedWrap() && RBO->hasNoUnsignedWrap();

         Пример 4. Проект Notepad++. Неправильная проверка состояния.

         bool _isPointXValid;
         bool _isPointYValid;
         ...
         bool isPointValid() {
           return _isPointXValid && _isPointXValid;
         };

         Ошибка найдена с помощью диагностики V501: There are identical sub-expressions to the left and to
         the right of the '&&' operator. _isPointXValid && _isPointXValid

         Дважды используется имя '_isPointXValid'. На самом деле, функция должна вернуть:
         "_isPointXValid && _isPointYValid".

         Пример 5. Проект StrongDC++. Неудачная проверка наличия rn.

         static void getContentLengthAndHeaderLength(...)
         {
           ...
           while(line[linelen] != 'r' && line[linelen] != 'r')
           ...
         }

         Ошибка найдена с помощью диагностики V501: There are identical sub-expressions 'line [linelen] !=
         'r'' to the left and to the right of the '&&' operator. miniupnpc miniupnpc.c 153

         Из-за опечатки дважды проверяем наличие символа 'r'. На самом деле еще должно проверяться
         наличие символа 'n'.

         Пример 6. Проект G3D Content Pak. Не там поставлена круглая закрывающаяся скобка.



Стр. 23 из 48                                                                                              28.10.2011 14:06
Реклама PVS-Studio - статический анализ кода на языке Си и Си++                        file:///E:/PVS-Studio_detects_ru.html


         bool Matrix4::operator==(const Matrix4& other) const {
           if (memcmp(this, &other, sizeof(Matrix4) == 0)) {
             return true;
           }
           ...
         }

         Ошибка найдена с помощью диагностики V575: The 'memcmp' function processes '0' elements.
         Inspect the 'third' argument. graphics3D matrix4.cpp 269

         Одна круглая скобка закрывается не там, где необходимо. Получается, что размер сравниваемой
         области памяти вычисляется выражением "sizeof(Matrix4) == 0". Это выражение всегда даёт в
         результате значение 'false'. Затем 'false' превращается в целочисленное значение, равное 0.
         Корректный код:

         if (memcmp(this, &other, sizeof(Matrix4)) == 0) {

         Пример 7. Проект QT. Ошибка копирования членов структуры.

         PassRefPtr<Structure>
         Structure::getterSetterTransition(Structure* structure)
         {
           ...
           transition->m_propertyStorageCapacity =
             structure->m_propertyStorageCapacity;
           transition->m_hasGetterSetterProperties =
             transition->m_hasGetterSetterProperties;
           transition->m_hasNonEnumerableProperties =
             structure->m_hasNonEnumerableProperties;
           transition->m_specificFunctionThrashCount =
             structure->m_specificFunctionThrashCount;
           ...
         }

         Ошибка найдена с помощью диагностики V570: The 'transition->m_hasGetterSetterProperties'
         variable is assigned to itself. QtScript structure.cpp 512

         Рассматривая подобный код, очень сложно заметить ошибку. Однако, она здесь есть. Поле
         'm_hasGetterSetterProperties' копируется само в себя. Корректный код должен выглядеть так:

         transition->m_hasGetterSetterProperties =
           structure->m_hasGetterSetterProperties;

         Пример 8. Проект Apache HTTP Server. Лишний оператор sizeof.

         PSECURITY_ATTRIBUTES GetNullACL(void)
         {
           PSECURITY_ATTRIBUTES sa;
           sa = (PSECURITY_ATTRIBUTES)
             LocalAlloc(LPTR, sizeof(SECURITY_ATTRIBUTES));
           sa->nLength = sizeof(sizeof(SECURITY_ATTRIBUTES));
           ...
         }

         Ошибка найдена с помощью диагностики V568: It's odd that the argument of sizeof() operator is the
         'sizeof (SECURITY_ATTRIBUTES)' expression. libhttpd util_win32.c 115

         В поле 'nLength' должен был записан размер структуры 'SECURITY_ATTRIBUTES'. В коде
         допущена опечатка. Оператор 'sizeof' здесь используется два раза. Как результат, в поле 'nLength'
         записывается размер, которыё имеет тип 'size_t'. Корректный код:



Стр. 24 из 48                                                                                             28.10.2011 14:06
Реклама PVS-Studio - статический анализ кода на языке Си и Си++                         file:///E:/PVS-Studio_detects_ru.html


         sa->nLength = sizeof(SECURITY_ATTRIBUTES);

         Пример 9. Проект FCE Ultra. Двойное объявление переменной.

         int iNesSaveAs(char* name)
         {
           ...
           fp = fopen(name,"wb");
           int x = 0;
           if (!fp)
             int x = 1;
           ...
         }

         Ошибка найдена с помощью диагностики V561: It's probably better to assign value to 'x' variable than
         to declare it anew. Previous daclaration: ines.cpp, line 960. fceuxines.cpp 962

         Переменная 'x' должна хранить информацию, удалось ли открыть файл или нет. Из-за опечатки,
         вместо присваивания переменной единицы создается и инициализируется новая переменная с
         именем 'x'. Корректный код, должен был быть таким:

         if (!fp)
           x = 1;

         Пример 10. Проект Notepad++. Использование оператора &&, вместо &.
         TCHAR GetASCII(WPARAM wParam, LPARAM lParam)
         {
           ...
           result=ToAscii(wParam,
             (lParam >> 16) && 0xff, keys,&dwReturnedValue,0);
           ...
         }

         Ошибка найдена с помощью диагностики V560: A part of conditional expression is always true: 0xff.
         notepadPlus babygrid.cpp 694

         Выражение "(lParam >> 16) && 0xff" не имеет никакого практического смысла и всегда равно
         значению 1 (true). Здесь опечатка заключается в том, что используется оператор '&&', хотя должен
         был использоваться оператор '&'.

         Пример 11. Проект WinDjView. Недописанное условие.

         inline bool IsValidChar(int c)
         {
           return c == 0x9 || 0xA || c == 0xD || c >= 0x20 &&
                  c <= 0xD7FF || c >= 0xE000 && c <= 0xFFFD ||
                  c >= 0x10000 && c <= 0x10FFFF;
         }

         Ошибка найдена с помощью диагностики V560: A part of conditional expression is always true: 0xA.
         WinDjView xmlparser.cpp 45 False

         Функция IsValidChar всегда возвращает значение 'true'. Из-за опечатки, в одном месте пропущено
         сравнение: "... || 0xA || ...".

         Пример 12. Проект Fennec Media Project. Лишняя точка с запятой.

         int settings_default(void)
         {



Стр. 25 из 48                                                                                              28.10.2011 14:06
Реклама PVS-Studio - статический анализ кода на языке Си и Си++                            file:///E:/PVS-Studio_detects_ru.html


             ...
             for(i=0; i<16; i++);
               for(j=0; j<32; j++)
               {
                 settings.conversion.equalizer_bands.boost[i][j] = 0.0;
                 settings.conversion.equalizer_bands.preamp[i]   = 0.0;
               }
         }

         Ошибка найдена с помощью диагностики V529: Odd semicolon ';' after 'for' operator. settings.c 483

         Про то, как опасна лишняя точка с запятой ';' знают все программисты на Си и Си++. К
         сожалению, это знание не мешает делать подобные опечатки. После первого оператора 'for' стоит
         лишняя точка с запятой, что делает этот фрагмент программы неработоспособным.

         Пример 13. Проект QT. Забытый оператор break.

         int QCleanlooksStyle::pixelMetric(...)
         {
           ...
           case PM_SpinBoxFrameWidth:
             ret = 3;
             break;
           case PM_MenuBarItemSpacing:
             ret = 6;
           case PM_MenuBarHMargin:
             ret = 0;
             break;
           ...
         }

         Ошибка найдена с помощью диагностики: V519: The 'ret' variable is assigned values twice
         successively. Perhaps this is a mistake. Check lines: 3765, 3767. QtGui qcleanlooksstyle.cpp 3767

         Классическая ошибка - пропущен 'break' внутри оператора 'switch'. Думаю, комментарии здесь
         излишни.

         Пример 14. Проект Miranda IM. Присваивание вместо сравнения.
         int FindItem(...)
         {
           ...
           int ret;
           ret=FindItem(hwnd,dat,hItem,
                        (struct ClcContact ** )&z,
                        (struct ClcGroup ** )&isv,NULL);
           if (ret=0) {return (0);}
           ...
         }

         Ошибка найдена с помощью диагностики V559: Suspicious assignment inside the condition
         expression of 'if' operator: ret = 0. clist_mw clcidents.c 179

         Опечатка находится внутри условия оператора 'if'. Вместо '==' написано просто '='. Функция
         некорректно обработает ситуацию, когда некий элемент не будет найден.

         Пример 15. Проект IPP Samples. Некорректный индекс.

         struct AVS_MB_INFO
         {
           ...



Стр. 26 из 48                                                                                                 28.10.2011 14:06
Реклама PVS-Studio - статический анализ кода на языке Си и Си++                       file:///E:/PVS-Studio_detects_ru.html


           Ipp8u refIdx[AVS_DIRECTIONS][4];
           ...
         };

         void AVSCompressor::GetRefIndiciesBSlice(void){
           ...
           if (m_pMbInfo->predType[0] & predType)
           {
             m_refIdx[iRefNum] = m_pMbInfo->refIdx[dir][0];
             iRefNum += 1;
           }
           if (m_pMbInfo->predType[1] & predType)
           {
             m_refIdx[iRefNum] = m_pMbInfo->refIdx[dir][1];
             iRefNum += 1;
           }
           if (m_pMbInfo->predType[2] & predType)
           {
             m_refIdx[iRefNum] = m_pMbInfo->refIdx[dir][2];
             iRefNum += 1;
           }
           if (m_pMbInfo->predType[3] & predType)
           {
             m_refIdx[iRefNum] = m_pMbInfo->refIdx[dir][30];
             iRefNum += 1;
           }
           ...
         }

         Ошибка найдена с помощью диагностики V557: Array overrun is possible. The '30' index is pointing
         beyond array bound. avs_enc umc_avs_enc_compressor_enc_b.cpp 495

         Обратите внимание вот на этот фрагмент: "m_pMbInfo->refIdx[dir][30]". Из-за опечатки вместо
         индекса 3 написано число 30. Кстати, этот пример хорошо показывает относительность разделения
         в статье ошибок по типам. Эту ошибку вполне можно отнести к разделу "Ошибки работы с
         массивами и строками". Деление условно и сделано, чтобы показать разнородность ошибок,
         которые может найти анализатор PVS-Studio.

         Пример 16. Проект ReactOS. Опечатка в макросе.

         #define SWAP(a,b,c)        c = a;
                                    a = b;
                                    a = c

         Ошибка найдена с помощью диагностики V519: The 'v2' variable is assigned values twice
         successively. Perhaps this is a mistake. Check lines: 343, 343. win32k gradient.c 343

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

         #define SWAP(a,b,c)        c = a;
                                    a = b;
                                    b = c

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




Стр. 27 из 48                                                                                            28.10.2011 14:06
Реклама PVS-Studio - статический анализ кода на языке Си и Си++                                file:///E:/PVS-Studio_detects_ru.html



         Неверное использование базовых функций и классов

         Пример 1. Проект Fennec Media Project. Отсутствие двух терминальных нулей.

         int JoiningProc(HWND hwnd,UINT uMsg,
           WPARAM wParam,LPARAM lParam)
         {
           ...
           OPENFILENAME lofn;
           memset(&lofn, 0, sizeof(lofn));
           ...
           lofn.lpstrFilter = uni("All Files (*.*)0*.*");
           ...
         }

         Ошибка найдена с помощью диагностики V540: Member 'lpstrFilter' should point to string terminated
         by two 0 characters. base windows.c 5309

         В Windows API есть структуры, в которых указатели на строки должны заканчиваться двойным
         нулем. Именно на такую строку и указывает член 'lpstrFilter' в структуре OPENFILENAME.

         Описание 'lpstrFilter' в MSDN:

         LPCTSTR

         A buffer containing pairs of null-terminated filter strings. The last string in the buffer must be terminated
         by two NULL characters.

         Если забыть написать в конце дополнительный ноль, то диалог работы с файлами в поле фильтров
         можем содержать мусор. Исправленный код:

         lofn.lpstrFilter = uni("All Files (*.*)0*.*0");

         Пример 2. Проект TortoiseSVN. Неверное использование функции 'remove'.

         STDMETHODIMP CShellExt::Initialize(....)
         {
           ...
           ignoredprops = UTF8ToWide(st.c_str());
           // remove all escape chars ('')
           std::remove(ignoredprops.begin(), ignoredprops.end(), '');
           break;
           ...
         }

         Ошибка найдена с помощью диагностики V530: The return value of function 'remove' is required to be
         utilized. contextmenu.cpp 442

         Функция std::remove не удаляет элементы из контейнера. Она только сдвигает элементы и
         возвращает итератор на начало мусора. Пусть мы имеем контейнер vector<int>, содержащий
         элементы 1,2,3,1,2,3,1,2,3. Если выполнить код "remove( v.begin(), v.end(), 2 )", то контейнер будет
         содержать элементы 1,3,1,3,X,X,X, где X - некий мусор. При этом функция вернет итератор на
         первый мусорный элемент, и если мы хотим удалить эти мусорные элементы, то должны написать
         код: "v.erase(remove(v.begin(), v.end(), 2), v.end())".

         Пример 3. Проект TortoiseSVN. Использование функции 'empty' вместо 'clear'.

         CMailMsg& CMailMsg::SetFrom(string sAddress,
                                     string sName)


Стр. 28 из 48                                                                                                     28.10.2011 14:06
Реклама PVS-Studio - статический анализ кода на языке Си и Си++
Реклама PVS-Studio - статический анализ кода на языке Си и Си++
Реклама PVS-Studio - статический анализ кода на языке Си и Си++
Реклама PVS-Studio - статический анализ кода на языке Си и Си++
Реклама PVS-Studio - статический анализ кода на языке Си и Си++
Реклама PVS-Studio - статический анализ кода на языке Си и Си++
Реклама PVS-Studio - статический анализ кода на языке Си и Си++
Реклама PVS-Studio - статический анализ кода на языке Си и Си++
Реклама PVS-Studio - статический анализ кода на языке Си и Си++
Реклама PVS-Studio - статический анализ кода на языке Си и Си++
Реклама PVS-Studio - статический анализ кода на языке Си и Си++
Реклама PVS-Studio - статический анализ кода на языке Си и Си++
Реклама PVS-Studio - статический анализ кода на языке Си и Си++
Реклама PVS-Studio - статический анализ кода на языке Си и Си++
Реклама PVS-Studio - статический анализ кода на языке Си и Си++
Реклама PVS-Studio - статический анализ кода на языке Си и Си++
Реклама PVS-Studio - статический анализ кода на языке Си и Си++
Реклама PVS-Studio - статический анализ кода на языке Си и Си++
Реклама PVS-Studio - статический анализ кода на языке Си и Си++
Реклама PVS-Studio - статический анализ кода на языке Си и Си++

More Related Content

What's hot

Трудности сравнения анализаторов кода или не забывайте об удобстве использования
Трудности сравнения анализаторов кода или не забывайте об удобстве использованияТрудности сравнения анализаторов кода или не забывайте об удобстве использования
Трудности сравнения анализаторов кода или не забывайте об удобстве использования
Tatyanazaxarova
 
Поиск ловушек в Си/Си++ коде при переносе приложений под 64-битную версию Win...
Поиск ловушек в Си/Си++ коде при переносе приложений под 64-битную версию Win...Поиск ловушек в Си/Си++ коде при переносе приложений под 64-битную версию Win...
Поиск ловушек в Си/Си++ коде при переносе приложений под 64-битную версию Win...
Tatyanazaxarova
 
PVS-Studio в 2021
PVS-Studio в 2021PVS-Studio в 2021
PVS-Studio в 2021
Andrey Karpov
 
TAP
TAPTAP
TAP
miraj84
 
Константин Книжник: статический анализ, взгляд со стороны
Константин Книжник: статический анализ, взгляд со стороныКонстантин Книжник: статический анализ, взгляд со стороны
Константин Книжник: статический анализ, взгляд со стороны
Tatyanazaxarova
 
Сравнение PVS-Studio с другими анализаторами кода
Сравнение PVS-Studio с другими анализаторами кодаСравнение PVS-Studio с другими анализаторами кода
Сравнение PVS-Studio с другими анализаторами кода
Tatyanazaxarova
 
Отладка и оптимизация многопоточных OpenMP-программ
Отладка и оптимизация многопоточных OpenMP-программОтладка и оптимизация многопоточных OpenMP-программ
Отладка и оптимизация многопоточных OpenMP-программ
Tatyanazaxarova
 
Построение систем автоматического протоколирования Си/Си++ кода
Построение систем автоматического протоколирования Си/Си++ кодаПостроение систем автоматического протоколирования Си/Си++ кода
Построение систем автоматического протоколирования Си/Си++ кода
Tatyanazaxarova
 
Специфика тестирования проектов с открытым исходным кодом
Специфика тестирования проектов с открытым исходным кодомСпецифика тестирования проектов с открытым исходным кодом
Специфика тестирования проектов с открытым исходным кодом
SQALab
 
Применение статического анализа кода в преподавании и в разработке свободного ПО
Применение статического анализа кода в преподавании и в разработке свободного ПОПрименение статического анализа кода в преподавании и в разработке свободного ПО
Применение статического анализа кода в преподавании и в разработке свободного ПО
Andrey Karpov
 
Урок 25. Практическое знакомство с паттернами 64-битных ошибок
Урок 25. Практическое знакомство с паттернами 64-битных ошибокУрок 25. Практическое знакомство с паттернами 64-битных ошибок
Урок 25. Практическое знакомство с паттернами 64-битных ошибок
Tatyanazaxarova
 
Как создать качественный статический анализатор
Как создать качественный статический анализаторКак создать качественный статический анализатор
Как создать качественный статический анализатор
Andrey Karpov
 
Интервью с Дмитрием Вьюковым – автором верификатора Relacy Race Detector (RRD)
Интервью с Дмитрием Вьюковым – автором верификатора Relacy Race Detector (RRD)Интервью с Дмитрием Вьюковым – автором верификатора Relacy Race Detector (RRD)
Интервью с Дмитрием Вьюковым – автором верификатора Relacy Race Detector (RRD)
Tatyanazaxarova
 
Особенности тестирования открытого ПО
Особенности тестирования открытого ПООсобенности тестирования открытого ПО
Особенности тестирования открытого ПОAlexey Lyanguzov
 
Проблемы тестирования 64-битных приложений
Проблемы тестирования 64-битных приложенийПроблемы тестирования 64-битных приложений
Проблемы тестирования 64-битных приложений
Tatyanazaxarova
 
Net framework
Net frameworkNet framework
Net framework
poverhnost
 
Статический анализ и ROI
Статический анализ и ROIСтатический анализ и ROI
Статический анализ и ROI
Tatyanazaxarova
 
Рефакторинг и второе рождение проекта на примере Zend Framework 2.0
Рефакторинг и второе рождение проекта на примере Zend Framework 2.0Рефакторинг и второе рождение проекта на примере Zend Framework 2.0
Рефакторинг и второе рождение проекта на примере Zend Framework 2.0
AlexeyParhomenko
 
Как не подавиться большим старым проектом. Юрий Минаев ➠ CoreHard Autumn 2019
Как не подавиться большим старым проектом. Юрий Минаев ➠  CoreHard Autumn 2019Как не подавиться большим старым проектом. Юрий Минаев ➠  CoreHard Autumn 2019
Как не подавиться большим старым проектом. Юрий Минаев ➠ CoreHard Autumn 2019
corehard_by
 
СОВМЕСТНОЕ ПРИМЕНЕНИЕ КОНТРАКТОВ И ВЕРИФИКАЦИИ ДЛЯ ПОВЫШЕНИЯ КАЧЕСТВА АВТОМАТ...
СОВМЕСТНОЕ ПРИМЕНЕНИЕ КОНТРАКТОВ И ВЕРИФИКАЦИИ ДЛЯ ПОВЫШЕНИЯ КАЧЕСТВА АВТОМАТ...СОВМЕСТНОЕ ПРИМЕНЕНИЕ КОНТРАКТОВ И ВЕРИФИКАЦИИ ДЛЯ ПОВЫШЕНИЯ КАЧЕСТВА АВТОМАТ...
СОВМЕСТНОЕ ПРИМЕНЕНИЕ КОНТРАКТОВ И ВЕРИФИКАЦИИ ДЛЯ ПОВЫШЕНИЯ КАЧЕСТВА АВТОМАТ...
ITMO University
 

What's hot (20)

Трудности сравнения анализаторов кода или не забывайте об удобстве использования
Трудности сравнения анализаторов кода или не забывайте об удобстве использованияТрудности сравнения анализаторов кода или не забывайте об удобстве использования
Трудности сравнения анализаторов кода или не забывайте об удобстве использования
 
Поиск ловушек в Си/Си++ коде при переносе приложений под 64-битную версию Win...
Поиск ловушек в Си/Си++ коде при переносе приложений под 64-битную версию Win...Поиск ловушек в Си/Си++ коде при переносе приложений под 64-битную версию Win...
Поиск ловушек в Си/Си++ коде при переносе приложений под 64-битную версию Win...
 
PVS-Studio в 2021
PVS-Studio в 2021PVS-Studio в 2021
PVS-Studio в 2021
 
TAP
TAPTAP
TAP
 
Константин Книжник: статический анализ, взгляд со стороны
Константин Книжник: статический анализ, взгляд со стороныКонстантин Книжник: статический анализ, взгляд со стороны
Константин Книжник: статический анализ, взгляд со стороны
 
Сравнение PVS-Studio с другими анализаторами кода
Сравнение PVS-Studio с другими анализаторами кодаСравнение PVS-Studio с другими анализаторами кода
Сравнение PVS-Studio с другими анализаторами кода
 
Отладка и оптимизация многопоточных OpenMP-программ
Отладка и оптимизация многопоточных OpenMP-программОтладка и оптимизация многопоточных OpenMP-программ
Отладка и оптимизация многопоточных OpenMP-программ
 
Построение систем автоматического протоколирования Си/Си++ кода
Построение систем автоматического протоколирования Си/Си++ кодаПостроение систем автоматического протоколирования Си/Си++ кода
Построение систем автоматического протоколирования Си/Си++ кода
 
Специфика тестирования проектов с открытым исходным кодом
Специфика тестирования проектов с открытым исходным кодомСпецифика тестирования проектов с открытым исходным кодом
Специфика тестирования проектов с открытым исходным кодом
 
Применение статического анализа кода в преподавании и в разработке свободного ПО
Применение статического анализа кода в преподавании и в разработке свободного ПОПрименение статического анализа кода в преподавании и в разработке свободного ПО
Применение статического анализа кода в преподавании и в разработке свободного ПО
 
Урок 25. Практическое знакомство с паттернами 64-битных ошибок
Урок 25. Практическое знакомство с паттернами 64-битных ошибокУрок 25. Практическое знакомство с паттернами 64-битных ошибок
Урок 25. Практическое знакомство с паттернами 64-битных ошибок
 
Как создать качественный статический анализатор
Как создать качественный статический анализаторКак создать качественный статический анализатор
Как создать качественный статический анализатор
 
Интервью с Дмитрием Вьюковым – автором верификатора Relacy Race Detector (RRD)
Интервью с Дмитрием Вьюковым – автором верификатора Relacy Race Detector (RRD)Интервью с Дмитрием Вьюковым – автором верификатора Relacy Race Detector (RRD)
Интервью с Дмитрием Вьюковым – автором верификатора Relacy Race Detector (RRD)
 
Особенности тестирования открытого ПО
Особенности тестирования открытого ПООсобенности тестирования открытого ПО
Особенности тестирования открытого ПО
 
Проблемы тестирования 64-битных приложений
Проблемы тестирования 64-битных приложенийПроблемы тестирования 64-битных приложений
Проблемы тестирования 64-битных приложений
 
Net framework
Net frameworkNet framework
Net framework
 
Статический анализ и ROI
Статический анализ и ROIСтатический анализ и ROI
Статический анализ и ROI
 
Рефакторинг и второе рождение проекта на примере Zend Framework 2.0
Рефакторинг и второе рождение проекта на примере Zend Framework 2.0Рефакторинг и второе рождение проекта на примере Zend Framework 2.0
Рефакторинг и второе рождение проекта на примере Zend Framework 2.0
 
Как не подавиться большим старым проектом. Юрий Минаев ➠ CoreHard Autumn 2019
Как не подавиться большим старым проектом. Юрий Минаев ➠  CoreHard Autumn 2019Как не подавиться большим старым проектом. Юрий Минаев ➠  CoreHard Autumn 2019
Как не подавиться большим старым проектом. Юрий Минаев ➠ CoreHard Autumn 2019
 
СОВМЕСТНОЕ ПРИМЕНЕНИЕ КОНТРАКТОВ И ВЕРИФИКАЦИИ ДЛЯ ПОВЫШЕНИЯ КАЧЕСТВА АВТОМАТ...
СОВМЕСТНОЕ ПРИМЕНЕНИЕ КОНТРАКТОВ И ВЕРИФИКАЦИИ ДЛЯ ПОВЫШЕНИЯ КАЧЕСТВА АВТОМАТ...СОВМЕСТНОЕ ПРИМЕНЕНИЕ КОНТРАКТОВ И ВЕРИФИКАЦИИ ДЛЯ ПОВЫШЕНИЯ КАЧЕСТВА АВТОМАТ...
СОВМЕСТНОЕ ПРИМЕНЕНИЕ КОНТРАКТОВ И ВЕРИФИКАЦИИ ДЛЯ ПОВЫШЕНИЯ КАЧЕСТВА АВТОМАТ...
 

Viewers also liked

100個信心的真理
100個信心的真理100個信心的真理
100個信心的真理Peter Chang
 
What Third Generation Blogging Means To You
What Third Generation Blogging Means To YouWhat Third Generation Blogging Means To You
What Third Generation Blogging Means To You
Compendium
 
EENG512FinalPresentation_DanielKuntz
EENG512FinalPresentation_DanielKuntzEENG512FinalPresentation_DanielKuntz
EENG512FinalPresentation_DanielKuntzDaniel K
 
Bayesian Depth-from-Defocus with Shading Constraints
Bayesian Depth-from-Defocus with Shading ConstraintsBayesian Depth-from-Defocus with Shading Constraints
Bayesian Depth-from-Defocus with Shading ConstraintsAaron Karper
 
PVS-Studio for Linux (CoreHard presentation)
PVS-Studio for Linux (CoreHard presentation)PVS-Studio for Linux (CoreHard presentation)
PVS-Studio for Linux (CoreHard presentation)
Andrey Karpov
 

Viewers also liked (7)

100個信心的真理
100個信心的真理100個信心的真理
100個信心的真理
 
What Third Generation Blogging Means To You
What Third Generation Blogging Means To YouWhat Third Generation Blogging Means To You
What Third Generation Blogging Means To You
 
Raskar Mar09 Nesosa
Raskar Mar09 NesosaRaskar Mar09 Nesosa
Raskar Mar09 Nesosa
 
EENG512FinalPresentation_DanielKuntz
EENG512FinalPresentation_DanielKuntzEENG512FinalPresentation_DanielKuntz
EENG512FinalPresentation_DanielKuntz
 
Raskar COSI invited talk Oct 2009
Raskar COSI invited talk Oct 2009Raskar COSI invited talk Oct 2009
Raskar COSI invited talk Oct 2009
 
Bayesian Depth-from-Defocus with Shading Constraints
Bayesian Depth-from-Defocus with Shading ConstraintsBayesian Depth-from-Defocus with Shading Constraints
Bayesian Depth-from-Defocus with Shading Constraints
 
PVS-Studio for Linux (CoreHard presentation)
PVS-Studio for Linux (CoreHard presentation)PVS-Studio for Linux (CoreHard presentation)
PVS-Studio for Linux (CoreHard presentation)
 

Similar to Реклама PVS-Studio - статический анализ кода на языке Си и Си++

Статический анализатор кода PVS-Studio
Статический анализатор кода PVS-StudioСтатический анализатор кода PVS-Studio
Статический анализатор кода PVS-Studio
cppclimber
 
PVS-Studio, решение для разработки современных ресурсоемких приложений
PVS-Studio, решение для разработки современных ресурсоемких приложенийPVS-Studio, решение для разработки современных ресурсоемких приложений
PVS-Studio, решение для разработки современных ресурсоемких приложений
Tatyanazaxarova
 
Трепещи, мир! Мы выпустили PVS-Studio 4.00 с бесплатным анализатором общего н...
Трепещи, мир! Мы выпустили PVS-Studio 4.00 с бесплатным анализатором общего н...Трепещи, мир! Мы выпустили PVS-Studio 4.00 с бесплатным анализатором общего н...
Трепещи, мир! Мы выпустили PVS-Studio 4.00 с бесплатным анализатором общего н...
Tatyanazaxarova
 
Использование анализатора PVS-Studio в процессе инкрементальной сборки в Micr...
Использование анализатора PVS-Studio в процессе инкрементальной сборки в Micr...Использование анализатора PVS-Studio в процессе инкрементальной сборки в Micr...
Использование анализатора PVS-Studio в процессе инкрементальной сборки в Micr...
Tatyanazaxarova
 
Облегчаем процесс разработки с помощью статического анализа кода: Наш опыт
Облегчаем процесс разработки с помощью статического анализа кода: Наш опытОблегчаем процесс разработки с помощью статического анализа кода: Наш опыт
Облегчаем процесс разработки с помощью статического анализа кода: Наш опыт
Andrey Karpov
 
статические анализаторы кода за и против
статические анализаторы кода  за и противстатические анализаторы кода  за и против
статические анализаторы кода за и противRoman Kalita
 
Сравнение диагностических возможностей анализаторов при проверке 64-битного кода
Сравнение диагностических возможностей анализаторов при проверке 64-битного кодаСравнение диагностических возможностей анализаторов при проверке 64-битного кода
Сравнение диагностических возможностей анализаторов при проверке 64-битного кода
Tatyanazaxarova
 
Разница в подходах анализа кода компилятором и выделенным инструментом
Разница в подходах анализа кода компилятором и выделенным инструментомРазница в подходах анализа кода компилятором и выделенным инструментом
Разница в подходах анализа кода компилятором и выделенным инструментом
Tatyanazaxarova
 
Статический анализ кода: борьба с удорожанием ошибок
Статический анализ кода: борьба с удорожанием ошибокСтатический анализ кода: борьба с удорожанием ошибок
Статический анализ кода: борьба с удорожанием ошибок
Andrey Karpov
 
Коллекция примеров 64-битных ошибок в реальных программах
Коллекция примеров 64-битных ошибок в реальных программахКоллекция примеров 64-битных ошибок в реальных программах
Коллекция примеров 64-битных ошибок в реальных программах
Tatyanazaxarova
 
Разработка ресурсоемких приложений в среде Visual C++
Разработка ресурсоемких приложений в среде Visual C++Разработка ресурсоемких приложений в среде Visual C++
Разработка ресурсоемких приложений в среде Visual C++
Tatyanazaxarova
 
Юрий Василевский «Автоматизация в XCode»
Юрий Василевский «Автоматизация в XCode»Юрий Василевский «Автоматизация в XCode»
Юрий Василевский «Автоматизация в XCode»
Yandex
 
Юрий Василевский "Автоматизация в XCode"
Юрий Василевский "Автоматизация в XCode"Юрий Василевский "Автоматизация в XCode"
Юрий Василевский "Автоматизация в XCode"
Yandex
 
64 бита для Си++ программистов: от /Wp64 к Viva64
64 бита для Си++ программистов: от /Wp64 к Viva6464 бита для Си++ программистов: от /Wp64 к Viva64
64 бита для Си++ программистов: от /Wp64 к Viva64
Tatyanazaxarova
 
Забытые проблемы разработки 64-битных программ
Забытые проблемы разработки 64-битных программЗабытые проблемы разработки 64-битных программ
Забытые проблемы разработки 64-битных программ
Tatyanazaxarova
 
CodeFest 2010. Уразов А. — Quality-Oriented Programming (Программирование, ор...
CodeFest 2010. Уразов А. — Quality-Oriented Programming (Программирование, ор...CodeFest 2010. Уразов А. — Quality-Oriented Programming (Программирование, ор...
CodeFest 2010. Уразов А. — Quality-Oriented Programming (Программирование, ор...CodeFest
 
Изменения в инфраструктуре инструментов для программистов
Изменения в инфраструктуре инструментов для программистовИзменения в инфраструктуре инструментов для программистов
Изменения в инфраструктуре инструментов для программистов
Tatyanazaxarova
 
Continous Integration
Continous IntegrationContinous Integration
Continous Integration
GetDev.NET
 
пр Спроси эксперта. Все, что вы хотели узнать про «дыры» в коде, но не у кого...
пр Спроси эксперта. Все, что вы хотели узнать про «дыры» в коде, но не у кого...пр Спроси эксперта. Все, что вы хотели узнать про «дыры» в коде, но не у кого...
пр Спроси эксперта. Все, что вы хотели узнать про «дыры» в коде, но не у кого...
Andrey Prozorov, CISM, CIPP/E, CDPSE. LA 27001
 

Similar to Реклама PVS-Studio - статический анализ кода на языке Си и Си++ (20)

Статический анализатор кода PVS-Studio
Статический анализатор кода PVS-StudioСтатический анализатор кода PVS-Studio
Статический анализатор кода PVS-Studio
 
PVS-Studio, решение для разработки современных ресурсоемких приложений
PVS-Studio, решение для разработки современных ресурсоемких приложенийPVS-Studio, решение для разработки современных ресурсоемких приложений
PVS-Studio, решение для разработки современных ресурсоемких приложений
 
Трепещи, мир! Мы выпустили PVS-Studio 4.00 с бесплатным анализатором общего н...
Трепещи, мир! Мы выпустили PVS-Studio 4.00 с бесплатным анализатором общего н...Трепещи, мир! Мы выпустили PVS-Studio 4.00 с бесплатным анализатором общего н...
Трепещи, мир! Мы выпустили PVS-Studio 4.00 с бесплатным анализатором общего н...
 
Использование анализатора PVS-Studio в процессе инкрементальной сборки в Micr...
Использование анализатора PVS-Studio в процессе инкрементальной сборки в Micr...Использование анализатора PVS-Studio в процессе инкрементальной сборки в Micr...
Использование анализатора PVS-Studio в процессе инкрементальной сборки в Micr...
 
Облегчаем процесс разработки с помощью статического анализа кода: Наш опыт
Облегчаем процесс разработки с помощью статического анализа кода: Наш опытОблегчаем процесс разработки с помощью статического анализа кода: Наш опыт
Облегчаем процесс разработки с помощью статического анализа кода: Наш опыт
 
статические анализаторы кода за и против
статические анализаторы кода  за и противстатические анализаторы кода  за и против
статические анализаторы кода за и против
 
Сравнение диагностических возможностей анализаторов при проверке 64-битного кода
Сравнение диагностических возможностей анализаторов при проверке 64-битного кодаСравнение диагностических возможностей анализаторов при проверке 64-битного кода
Сравнение диагностических возможностей анализаторов при проверке 64-битного кода
 
Разница в подходах анализа кода компилятором и выделенным инструментом
Разница в подходах анализа кода компилятором и выделенным инструментомРазница в подходах анализа кода компилятором и выделенным инструментом
Разница в подходах анализа кода компилятором и выделенным инструментом
 
Статический анализ кода: борьба с удорожанием ошибок
Статический анализ кода: борьба с удорожанием ошибокСтатический анализ кода: борьба с удорожанием ошибок
Статический анализ кода: борьба с удорожанием ошибок
 
Коллекция примеров 64-битных ошибок в реальных программах
Коллекция примеров 64-битных ошибок в реальных программахКоллекция примеров 64-битных ошибок в реальных программах
Коллекция примеров 64-битных ошибок в реальных программах
 
Разработка ресурсоемких приложений в среде Visual C++
Разработка ресурсоемких приложений в среде Visual C++Разработка ресурсоемких приложений в среде Visual C++
Разработка ресурсоемких приложений в среде Visual C++
 
Юрий Василевский «Автоматизация в XCode»
Юрий Василевский «Автоматизация в XCode»Юрий Василевский «Автоматизация в XCode»
Юрий Василевский «Автоматизация в XCode»
 
Юрий Василевский "Автоматизация в XCode"
Юрий Василевский "Автоматизация в XCode"Юрий Василевский "Автоматизация в XCode"
Юрий Василевский "Автоматизация в XCode"
 
64 бита для Си++ программистов: от /Wp64 к Viva64
64 бита для Си++ программистов: от /Wp64 к Viva6464 бита для Си++ программистов: от /Wp64 к Viva64
64 бита для Си++ программистов: от /Wp64 к Viva64
 
Sonar quality
Sonar qualitySonar quality
Sonar quality
 
Забытые проблемы разработки 64-битных программ
Забытые проблемы разработки 64-битных программЗабытые проблемы разработки 64-битных программ
Забытые проблемы разработки 64-битных программ
 
CodeFest 2010. Уразов А. — Quality-Oriented Programming (Программирование, ор...
CodeFest 2010. Уразов А. — Quality-Oriented Programming (Программирование, ор...CodeFest 2010. Уразов А. — Quality-Oriented Programming (Программирование, ор...
CodeFest 2010. Уразов А. — Quality-Oriented Programming (Программирование, ор...
 
Изменения в инфраструктуре инструментов для программистов
Изменения в инфраструктуре инструментов для программистовИзменения в инфраструктуре инструментов для программистов
Изменения в инфраструктуре инструментов для программистов
 
Continous Integration
Continous IntegrationContinous Integration
Continous Integration
 
пр Спроси эксперта. Все, что вы хотели узнать про «дыры» в коде, но не у кого...
пр Спроси эксперта. Все, что вы хотели узнать про «дыры» в коде, но не у кого...пр Спроси эксперта. Все, что вы хотели узнать про «дыры» в коде, но не у кого...
пр Спроси эксперта. Все, что вы хотели узнать про «дыры» в коде, но не у кого...
 

More from Andrey Karpov

60 антипаттернов для С++ программиста
60 антипаттернов для С++ программиста60 антипаттернов для С++ программиста
60 антипаттернов для С++ программиста
Andrey Karpov
 
60 terrible tips for a C++ developer
60 terrible tips for a C++ developer60 terrible tips for a C++ developer
60 terrible tips for a C++ developer
Andrey Karpov
 
Ошибки, которые сложно заметить на code review, но которые находятся статичес...
Ошибки, которые сложно заметить на code review, но которые находятся статичес...Ошибки, которые сложно заметить на code review, но которые находятся статичес...
Ошибки, которые сложно заметить на code review, но которые находятся статичес...
Andrey Karpov
 
PVS-Studio in 2021 - Error Examples
PVS-Studio in 2021 - Error ExamplesPVS-Studio in 2021 - Error Examples
PVS-Studio in 2021 - Error Examples
Andrey Karpov
 
PVS-Studio in 2021 - Feature Overview
PVS-Studio in 2021 - Feature OverviewPVS-Studio in 2021 - Feature Overview
PVS-Studio in 2021 - Feature Overview
Andrey Karpov
 
PVS-Studio в 2021 - Примеры ошибок
PVS-Studio в 2021 - Примеры ошибокPVS-Studio в 2021 - Примеры ошибок
PVS-Studio в 2021 - Примеры ошибок
Andrey Karpov
 
Make Your and Other Programmer’s Life Easier with Static Analysis (Unreal Eng...
Make Your and Other Programmer’s Life Easier with Static Analysis (Unreal Eng...Make Your and Other Programmer’s Life Easier with Static Analysis (Unreal Eng...
Make Your and Other Programmer’s Life Easier with Static Analysis (Unreal Eng...
Andrey Karpov
 
Best Bugs from Games: Fellow Programmers' Mistakes
Best Bugs from Games: Fellow Programmers' MistakesBest Bugs from Games: Fellow Programmers' Mistakes
Best Bugs from Games: Fellow Programmers' Mistakes
Andrey Karpov
 
Does static analysis need machine learning?
Does static analysis need machine learning?Does static analysis need machine learning?
Does static analysis need machine learning?
Andrey Karpov
 
Typical errors in code on the example of C++, C#, and Java
Typical errors in code on the example of C++, C#, and JavaTypical errors in code on the example of C++, C#, and Java
Typical errors in code on the example of C++, C#, and Java
Andrey Karpov
 
How to Fix Hundreds of Bugs in Legacy Code and Not Die (Unreal Engine 4)
How to Fix Hundreds of Bugs in Legacy Code and Not Die (Unreal Engine 4)How to Fix Hundreds of Bugs in Legacy Code and Not Die (Unreal Engine 4)
How to Fix Hundreds of Bugs in Legacy Code and Not Die (Unreal Engine 4)
Andrey Karpov
 
Game Engine Code Quality: Is Everything Really That Bad?
Game Engine Code Quality: Is Everything Really That Bad?Game Engine Code Quality: Is Everything Really That Bad?
Game Engine Code Quality: Is Everything Really That Bad?
Andrey Karpov
 
C++ Code as Seen by a Hypercritical Reviewer
C++ Code as Seen by a Hypercritical ReviewerC++ Code as Seen by a Hypercritical Reviewer
C++ Code as Seen by a Hypercritical Reviewer
Andrey Karpov
 
The Use of Static Code Analysis When Teaching or Developing Open-Source Software
The Use of Static Code Analysis When Teaching or Developing Open-Source SoftwareThe Use of Static Code Analysis When Teaching or Developing Open-Source Software
The Use of Static Code Analysis When Teaching or Developing Open-Source Software
Andrey Karpov
 
Static Code Analysis for Projects, Built on Unreal Engine
Static Code Analysis for Projects, Built on Unreal EngineStatic Code Analysis for Projects, Built on Unreal Engine
Static Code Analysis for Projects, Built on Unreal Engine
Andrey Karpov
 
Safety on the Max: How to Write Reliable C/C++ Code for Embedded Systems
Safety on the Max: How to Write Reliable C/C++ Code for Embedded SystemsSafety on the Max: How to Write Reliable C/C++ Code for Embedded Systems
Safety on the Max: How to Write Reliable C/C++ Code for Embedded Systems
Andrey Karpov
 
The Great and Mighty C++
The Great and Mighty C++The Great and Mighty C++
The Great and Mighty C++
Andrey Karpov
 
Static code analysis: what? how? why?
Static code analysis: what? how? why?Static code analysis: what? how? why?
Static code analysis: what? how? why?
Andrey Karpov
 
Zero, one, two, Freddy's coming for you
Zero, one, two, Freddy's coming for youZero, one, two, Freddy's coming for you
Zero, one, two, Freddy's coming for you
Andrey Karpov
 
PVS-Studio Is Now in Chocolatey: Checking Chocolatey under Azure DevOps
PVS-Studio Is Now in Chocolatey: Checking Chocolatey under Azure DevOpsPVS-Studio Is Now in Chocolatey: Checking Chocolatey under Azure DevOps
PVS-Studio Is Now in Chocolatey: Checking Chocolatey under Azure DevOps
Andrey Karpov
 

More from Andrey Karpov (20)

60 антипаттернов для С++ программиста
60 антипаттернов для С++ программиста60 антипаттернов для С++ программиста
60 антипаттернов для С++ программиста
 
60 terrible tips for a C++ developer
60 terrible tips for a C++ developer60 terrible tips for a C++ developer
60 terrible tips for a C++ developer
 
Ошибки, которые сложно заметить на code review, но которые находятся статичес...
Ошибки, которые сложно заметить на code review, но которые находятся статичес...Ошибки, которые сложно заметить на code review, но которые находятся статичес...
Ошибки, которые сложно заметить на code review, но которые находятся статичес...
 
PVS-Studio in 2021 - Error Examples
PVS-Studio in 2021 - Error ExamplesPVS-Studio in 2021 - Error Examples
PVS-Studio in 2021 - Error Examples
 
PVS-Studio in 2021 - Feature Overview
PVS-Studio in 2021 - Feature OverviewPVS-Studio in 2021 - Feature Overview
PVS-Studio in 2021 - Feature Overview
 
PVS-Studio в 2021 - Примеры ошибок
PVS-Studio в 2021 - Примеры ошибокPVS-Studio в 2021 - Примеры ошибок
PVS-Studio в 2021 - Примеры ошибок
 
Make Your and Other Programmer’s Life Easier with Static Analysis (Unreal Eng...
Make Your and Other Programmer’s Life Easier with Static Analysis (Unreal Eng...Make Your and Other Programmer’s Life Easier with Static Analysis (Unreal Eng...
Make Your and Other Programmer’s Life Easier with Static Analysis (Unreal Eng...
 
Best Bugs from Games: Fellow Programmers' Mistakes
Best Bugs from Games: Fellow Programmers' MistakesBest Bugs from Games: Fellow Programmers' Mistakes
Best Bugs from Games: Fellow Programmers' Mistakes
 
Does static analysis need machine learning?
Does static analysis need machine learning?Does static analysis need machine learning?
Does static analysis need machine learning?
 
Typical errors in code on the example of C++, C#, and Java
Typical errors in code on the example of C++, C#, and JavaTypical errors in code on the example of C++, C#, and Java
Typical errors in code on the example of C++, C#, and Java
 
How to Fix Hundreds of Bugs in Legacy Code and Not Die (Unreal Engine 4)
How to Fix Hundreds of Bugs in Legacy Code and Not Die (Unreal Engine 4)How to Fix Hundreds of Bugs in Legacy Code and Not Die (Unreal Engine 4)
How to Fix Hundreds of Bugs in Legacy Code and Not Die (Unreal Engine 4)
 
Game Engine Code Quality: Is Everything Really That Bad?
Game Engine Code Quality: Is Everything Really That Bad?Game Engine Code Quality: Is Everything Really That Bad?
Game Engine Code Quality: Is Everything Really That Bad?
 
C++ Code as Seen by a Hypercritical Reviewer
C++ Code as Seen by a Hypercritical ReviewerC++ Code as Seen by a Hypercritical Reviewer
C++ Code as Seen by a Hypercritical Reviewer
 
The Use of Static Code Analysis When Teaching or Developing Open-Source Software
The Use of Static Code Analysis When Teaching or Developing Open-Source SoftwareThe Use of Static Code Analysis When Teaching or Developing Open-Source Software
The Use of Static Code Analysis When Teaching or Developing Open-Source Software
 
Static Code Analysis for Projects, Built on Unreal Engine
Static Code Analysis for Projects, Built on Unreal EngineStatic Code Analysis for Projects, Built on Unreal Engine
Static Code Analysis for Projects, Built on Unreal Engine
 
Safety on the Max: How to Write Reliable C/C++ Code for Embedded Systems
Safety on the Max: How to Write Reliable C/C++ Code for Embedded SystemsSafety on the Max: How to Write Reliable C/C++ Code for Embedded Systems
Safety on the Max: How to Write Reliable C/C++ Code for Embedded Systems
 
The Great and Mighty C++
The Great and Mighty C++The Great and Mighty C++
The Great and Mighty C++
 
Static code analysis: what? how? why?
Static code analysis: what? how? why?Static code analysis: what? how? why?
Static code analysis: what? how? why?
 
Zero, one, two, Freddy's coming for you
Zero, one, two, Freddy's coming for youZero, one, two, Freddy's coming for you
Zero, one, two, Freddy's coming for you
 
PVS-Studio Is Now in Chocolatey: Checking Chocolatey under Azure DevOps
PVS-Studio Is Now in Chocolatey: Checking Chocolatey under Azure DevOpsPVS-Studio Is Now in Chocolatey: Checking Chocolatey under Azure DevOps
PVS-Studio Is Now in Chocolatey: Checking Chocolatey under Azure DevOps
 

Реклама PVS-Studio - статический анализ кода на языке Си и Си++

  • 1. Реклама PVS-Studio - статический анализ кода на языке Си и Си++ file:///E:/PVS-Studio_detects_ru.html Реклама PVS-Studio - статический анализ кода на языке Си и Си++ Авторы: Андрей Карпов, Евгений Рыжков Дата: 25.10.2011 Аннотация Что такое статический анализ кода Инструмент PVS-Studio Типы выявляемых дефектов Работа с отчетом PVS-Studio Инкрементальный анализ кода Возврат инвестиций при использовании PVS-Studio (ROI) Поддержка наших пользователей Примеры выявленных ошибок в различных open-source проектах Ошибки работы с массивами и строками Неопределенное поведение (Undefined behavior) Ошибки, связанные с приоритетом операций. Ошибки форматированного вывода Примеры выявленных опечаток в коде Неверное использование базовых функций и классов Примеры бессмысленного кода Всегда ложные или истинные условия Уязвимости в коде Copy-Paste Разное Заключение и вывод Различные ссылки Аннотация Этот документ рекламирует статический анализатор PVS-Studio. Описывается, как использование PVS-Studio уменьшит количество ошибок в коде проекта на языке C/C++/C++11 и сократит затраты на тестирование, отладку и сопровождение кода. Приводится большое количество примеров ошибок, найденных анализатором в различных Open-Source проектах. Документ описывает PVS-Studio на момент версии 4.38 от 12 октября 2011 и, как следствие, не отражает возможности следующих версий. Чтобы познакомиться с новыми возможностями, предлагаем посетить сайт продукта http://www.viva64.com или поискать обновленный вариант этой статьи. Что такое статический анализ кода Статический анализ кода - это методология выявления ошибок в программном обеспечении. Методология основана на быстром и эффективном просмотре программистом участков кода, помеченных статическим анализатором там, где потенциально может находиться ошибка. Другими словами инструмент для статического анализа определяет в тексте программы места, содержащие ошибки, предрасположенные к ошибкам или имеющие плохое форматирование. Стр. 1 из 48 28.10.2011 14:06
  • 2. Реклама PVS-Studio - статический анализ кода на языке Си и Си++ file:///E:/PVS-Studio_detects_ru.html Такие участки кода предоставляются программисту для изучения, и он может принять решение о модификации данного участка программы. Статический анализ кода отчасти схож с методикой обзоров кода (code review). Отличие в том, что роль экспертов здесь выполняет программное обеспечение. Конечно, возможности программы далеки от возможности команды людей. Но зато, программа неутомима, и её использование на несколько порядков дешевле по сравнению с обзорами кода. Статические анализаторы могут быть как общего назначения (например, PVS-Studio, Microsoft PREFast, Gimpel PC-Lint, Parasoft C++Test), так и специализированными для поиска определенных классов ошибок (например, Chord для верификации параллельных Java программ). Статические анализаторы обычно используются в компаниях с высокой культурой разработки и зрелыми процессами разработки программного обеспечения. Это связано с тем, что инструменты статического анализа требуют понимания принципов их работы, необходимости уделить некоторое время их изучению и интеграции в процесс разработки. Взамен они позволяют выявить большое количество ошибок на самых ранних этапах разработки программного кода. Основное преимущество использования статических анализаторов кода состоит в возможности существенного снижения стоимости устранения дефектов в программе. Чем раньше ошибка выявлена, тем меньше стоимость ее исправления. Так, согласно данным, приведенным в книге Макконнелла "Совершенный Код", исправление ошибки на этапе тестирования обойдется в десять раз дороже, чем на этапе конструирования (кодирования): Рисунок 1. Средняя стоимость исправления дефектов в зависимости от времени их внесения и обнаружения (данные для таблицы взяты из книги С. Макконнелла "Совершенный Код"). Инструменты статического анализа позволяют выявить большое количество ошибок этапа конструирования, что существенно снижает стоимость разработки всего проекта. Инструмент PVS-Studio PVS-Studio это легкий в изучении и использовании инструмент статического анализа кода. PVS-Studio представляет собой модуль расширения к среде программирования Visual Studio 2005/2008/2010. Впрочем, анализатор можно использовать и из командной строки, о чем более подробно можно узнать в документации. Основные характеристики PVS-Studio: Стр. 2 из 48 28.10.2011 14:06
  • 3. Реклама PVS-Studio - статический анализ кода на языке Си и Си++ file:///E:/PVS-Studio_detects_ru.html Поддерживаемые языки: С / C++ / С++11 (в тех рамках, в которых эти языки поддерживает компилятор Visual C++). Операционные системы: 32-битные и 64-битные версии Windows XP / 2003 / Vista / 2008 / 7. Системные требования: Системные требования к анализатору совпадают с требованиями к Microsoft Visual Studio. Режимы работы: Как расширение среды Visual Studio 2005/2008/2010. Запуск из командной строки (есть solution-файл / нет solution-файла). Примечание: работа PVS-Studio с Visual C++ Express Edition не возможна, поскольку эта система не поддерживает модули расширений. Интеграция с системами continuous integration: Есть. Сайт продукта: http://www.viva64.com/ru/ Документация: На русском и английском языке. Возможность скачать демонстрационную версию: Есть. Возможность приобретения: Онлайн. Поддержка: Оперативно оказывается программистами по электронной почте на русском и английском языке. Поддержка включает в себя доработки, помогающие интегрировать продукт в процесс разработки проекта. Учитываются пожелания пользователей по созданию новых диагностических правил. Типы выявляемых дефектов Диагностические сообщения PVS-Studio можно разделить на 5 групп: 1. Диагностика параллельных ошибок в OpenMP программах. Несмотря на то, что в 2006-2009 году компания Intel активно продвигала технологию OpenMP, она так и не нашла отклика в сердцах программистах и практически не используется. Мы решили оставить соответствующие диагностические правила, но далее не развивать это направление. Следовательно, на параллельных ошибках заострять внимание не будем и перейдем к более интересным возможностям анализатора. Интересующимся тематикой OpenMP предлагаем этот раздел сайта: http://www.viva64.com/ru/vivamp-tool/ . 2. Диагностика 64-битных ошибок PVS-Studio имеет, на наш взгляд, самый мощный в мире набор правил статического анализа, выявляющих 64-битные ошибки. Эти диагностические правила помогают перенести 32-битный код на 64-битную систему и контролировать написание нового 64-битного кода. На тему 64-битных ошибок мы написали множество интересных статей, с которыми можно познакомиться на нашем сайте: Коллекция примеров 64-битных ошибок в реальных программах: http://www.viva64.com /ru/a/0065/ 64-битный конь, который умеет считать: http://www.viva64.com/ru/a/0043/ Что такое size_t и ptrdiff_t: http://www.viva64.com/ru/a/0050/ Уроки разработки 64-битных приложений на языке Си/Си++: http://www.viva64.com/ru/l/ Стр. 3 из 48 28.10.2011 14:06
  • 4. Реклама PVS-Studio - статический анализ кода на языке Си и Си++ file:///E:/PVS-Studio_detects_ru.html В перечисленных статьях подробно рассмотрена тематика 64-битных дефектов, и здесь мы не будем на ней останавливаться. Приведем только один пример, чтобы дать понять о каких ошибках в этих статьях идёт речь: dgCollisionCompoundBreakable::dgCollisionCompoundBreakable(...) { ... dgInt32 faceOffsetHitogram[256]; dgSubMesh* mainSegmenst[256]; ... memset (faceOffsetHitogram, 0, sizeof(faceOffsetHitogram)); memset (mainSegmenst, 0, sizeof(faceOffsetHitogram)); ... } Этот код был обнаружен PVS-Studio в проекте Newton Game Dynamics. Обратите внимание на второй вызов функции 'memset'. Из-за случайной опечатки эта функция заполняет нулями 'sizeof(faceOffsetHitogram)' байт, а не 'sizeof(mainSegmenst)'. Почему эту ошибку мы называем 64-битной? Дело в том, что эта ошибка проявит себя только при компиляции кода в 64-битном режиме. В 32-битной программе размер указателей и типа 'dgInt32' совпадает. Это значит, что в 32-битной программе размер массивов faceOffsetHitogram и mainSegmenst совпадут. В 64-битной программе эти массивы занимают разное количество байт, а следовательно функция 'memset' заполнит только часть массива. 3. Выявление неэффективных конструкций PVS-Studio содержит ряд правил для выявления конструкций, код которых можно оптимизировать. Неэффективный код это, конечно, не ошибка, и каждый программист сам должен решить, использовать эти диагностические сообщения или нет. В качестве пояснения приведем простой пример: if ((strlen(directory) > 0) && (directory[strlen(directory)-1] != '')) Анализатор выдаст для этого кода предупреждение V804. Этот код можно оптимизировать, если предварительно вычислить длину строки и поместить её во временную переменную. Это не всегда нужно. Однако, если подобный код выполняется множество раз в цикле, такая оптимизация может быть весьма полезна. 4. Диагностические правила, имплементированные по заказу пользователей Эти правила достаточно специфичны и полезны только узкой группе пользователей. О них упомянуто, чтобы вы знали, что наша компания всегда готова откликнуться на любые пожелания наших клиентов! 5. Диагностические правила общего назначения Это самый интересный набор правил. Позволяет выявить множество интересных ошибок, начиная от опечаток и заканчивая потенциальными уязвимостями для атаки. Лучшей рекламой для программистов являются примеры исходного кода. Поэтому не будем писать абстрактные тексты о возможностях статического анализа, а покажем эти самые примеры на практике. Если вы стремитесь поскорее посмотреть их, то перейдите к разделу "Примеры выявленных ошибок в различных open-source проектах". Или ещё немного потерпите и прочитайте всю скромную хвалебную статью по порядку. Стр. 4 из 48 28.10.2011 14:06
  • 5. Реклама PVS-Studio - статический анализ кода на языке Си и Си++ file:///E:/PVS-Studio_detects_ru.html Работа с отчетом PVS-Studio Если вы работаете с анализатором в рамках среды Visual Studio, то в вашем распоряжении будет простой интерфейс, состоящий из 2 компонент: новое меню и интерактивное окно для работы с предупреждениями. 1. Меню PVS-Studio Рисунок 2. Меню PVS-Studio, интегрированное в Visual Studio 2005. С его помощью можно запустить анализ, сохранить/загрузить лог, изменить настройки и прочие функции, в которых любой программист сможет легко разобраться. 2. Интегративное окно с предупреждениями Рисунок 3. Окно PVS-Studio для работы с предупреждениями (кликните на картинку для просмотра полноценного снимка экрана) Функциональность окна: Навигация по коду. Осуществляется двойным щелчком мыши по сообщению с помощью иконок вперёд/назад или с помощью горячих клавиш 'Alt - [' и 'Alt - ]'. Стр. 5 из 48 28.10.2011 14:06
  • 6. Реклама PVS-Studio - статический анализ кода на языке Си и Си++ file:///E:/PVS-Studio_detects_ru.html Открытие документации для соответствующей ошибки. Необходимо щелкнуть мышкой на коде ошибки. Включение/выключение различных наборов предупреждений. Например, можно просмотреть только предупреждения первого уровня важности, относящиеся к 64-битным диагностикам. Различные способы сортировки и фильтрации сообщений. Возможен поиск определенных сообщений. Есть и другие мелкие возможности, такие как "пометка звездочкой" сообщений, вызвавших интерес. Для отдельных сообщений также доступно контекстное меню (наведите на сообщение и нажмите правую кнопку мыши). Например, с помощью него можно осуществить такую важную функцию, как пометить диагностику как ложную (Mark selected errors as False Alarms). Инкрементальный анализ кода PVS-Studio позволяет дешево внедрить статический анализ в процесс разработки. Если включен режим "Incremental Analysis after Build", то анализатор запускается сразу после компиляции и проверяет только те файлы, которые были "задеты" правками пользователя. То есть пользователь видит ошибки только в том коде, который он непосредственно пишет или затрагивает при рефакторинге. Программисту не надо беспокоиться о большом объеме кода, с которым он в данный момент не работает. Возможно, этому коду уже более 5 лет. Он практически не модифицируется и большинство дефектов в нем уже исправлено. Этот код не надо бросаться проверять в первую очередь, и анализатор этого и не делает. Программист будет видеть предупреждения только в свежем коде. А уж если у него будет дополнительное время, он всегда сможет проверить проект целиком, заглянув в самые редко посещаемые места. Инкрементальный анализ выполняется в фоновом режиме, и вы можете, не дожидаясь его завершения, заниматься другими действиями и правкой кода. Если анализатор что-то найдет, то он просигнализирует это сменой цвета иконки окна и всплывающим уведомлением. Рисунок 5. Всплывающее уведомление PVS-Studio. Конечно, мы все не любим всякие назойливые всплывающие уведомления. Но в данном случае оно будет явно полезно программисту и будет появляться редко, при условии, что он не злоупотребляет ошибками в коде. Попробуйте. Мы уверены, программистам понравится этот режим работы. Стр. 6 из 48 28.10.2011 14:06
  • 7. Реклама PVS-Studio - статический анализ кода на языке Си и Си++ file:///E:/PVS-Studio_detects_ru.html Возврат инвестиций при использовании PVS-Studio (ROI) Этот раздел на тот случай, если попробуете анализатор PVS-Studio и найдете только несколько ошибок. У вас возникнет вопрос, в чём польза от использования статического анализа, если он смог выявить только небольшое количество дефектов? Если это произошло, то вспомните про этот текст и ознакомьтесь со следующими 2 заметками: Лев Толстой и статический анализ кода: http://www.viva64.com/ru/b/0105/ Статический анализ и ROI: http://www.viva64.com/ru/b/0100/ Если совсем кратко, то польза статического анализа проявляется при его регулярном использовании, а не от случая к случаю. Те ошибки, которые мог бы легко и быстро обнаружить PVS-Studio, были уже исправлены с помощью таких дорогостоящих процедур, как отладка, тестирование или получение замечаний от пользователей. Поддержка наших пользователей С нашими клиентами общаются непосредственно разработчики анализатора, что позволяет быстро отвечать даже на сложные вопросы, связанные с программированием. Мы всегда готовы помочь в адаптации и интеграции PVS-Studio в процесс разработки, используемый в компании клиента. В качестве примера приведем несколько функциональных возможностей, реализованных по просьбе пользователей: создание файлов-отчетов в определенном формате; разработка скриптов (сценариев) для особых вариантов запуска PVS-Studio; доработка инструмента для взаимодействия с той или иной системой непрерывной интеграции или сборки; введение новых настроек в инструменте; проверка не всех файлов проекта/решения, а только некоторых (по именам или по времени модификации – к примеру, за последний день). Помимо консультаций по использованию PVS-Studio и помощи в интеграции статического анализа в ежедневный процесс разработки, мы учитываем пожелания наших пользователей по реализации новых диагностических правил. Примеры выявленных ошибок в различных open-source проектах Мы регулярно проверяем известные и не очень известные open-source проекты. Это делается для того, чтобы иметь возможность написать соответствующую рекламную заметку и протестировать работу анализатора PVS-Studio на новом коде. Многие читатели спрашивают, сообщаем ли мы авторам проектов о найденных ошибках. Да, в обязательном порядке. И так случается, что иногда после этого у нас появляется новый клиент. Примеры найденных ошибок будут разделены на несколько групп. Это деление весьма условно. Часто одну и ту же ошибку можно отнести одновременно к опечатке, к уязвимостям и некорректной работе с массивами. Поэтому группировкой ошибок по различным типам хотелось показать, что анализатор способен обнаруживать широкий спектр разнообразнейших дефектов. Из проверенных нами проектов, конечно, взято только по несколько ошибок. Если описывать все Стр. 7 из 48 28.10.2011 14:06
  • 8. Реклама PVS-Studio - статический анализ кода на языке Си и Си++ file:///E:/PVS-Studio_detects_ru.html найденные дефекты, то это уже будет справочник. Список проверенных проектов: Apache HTTP Server - http://httpd.apache.org/ Audacity - http://audacity.sourceforge.net/ Chromium - http://www.chromium.org/ Clang - http://clang-analyzer.llvm.org/ CMake - http://www.cmake.org/ Crystal Space 3D SDK - http://www.crystalspace3d.org/main/Main_Page Emule - http://www.emule.com/ FAR Manager - http://www.farmanager.com/ FCE Ultra - http://fceux.com/web/home.html Fennec Media Project - http://fennec.sourceforge.net/ G3D Content Pak - http://sourceforge.net/projects/g3d-cpp/ IPP Samples - http://www.viva64.com/go.php?url=449 Lugaru - http://www.wolfire.com/lugaru Miranda IM - http://www.miranda-im.org/ MySQL - http://www.mysql.com/ Newton Game Dynamics - http://newtondynamics.com/forum/newton.php Notepad++ - http://notepad-plus-plus.org/ Pixie - http://www.renderpixie.com/ PNG library - http://libpng.org/pub/png/ QT - http://qt.nokia.com/products/ ReactOS - http://www.reactos.org/en/ Shareaza - http://www.shareaza.com/ SMTP Client with SSL/TLS - http://www.codeproject.com/KB/IP/smtp_ssl.aspx StrongDC++ - http://strongdc.sourceforge.net/index.php?lang=eng Swiss-Army Knife of Trace - http://www.codeproject.com/KB/trace/tracetool.aspx TortoiseSVN - http://tortoisesvn.net/ Ultimate TCP/IP - http://www.codeproject.com/KB/MFC/UltimateTCPIP.aspx VirtualDub - http://www.virtualdub.org/ WinDjView - http://windjview.sourceforge.net/ WinMerge - http://winmerge.org/ Wolfenstein 3D - http://en.wikipedia.org/wiki/Wolfenstein_3D И некоторые другие. Стр. 8 из 48 28.10.2011 14:06
  • 9. Реклама PVS-Studio - статический анализ кода на языке Си и Си++ file:///E:/PVS-Studio_detects_ru.html Рисунок 6. Логотипы проверенных проектов Ошибки работы с массивами и строками Ошибки в обработке массивов и строк являются самым обширным классом дефектов в программах на языке Си/Си++. Это плата за возможность эффективной низкоуровневой работы с оперативной памятью. В статье будет показа лишь малая часть подобных ошибок, найденных анализатором PVS-Studio. Но думаем, что любой Си/Си++ программист понимает, как их много и как они коварны. Пример 1. Проект Wolfenstein 3D. Очистка только части объекта. void CG_RegisterItemVisuals( int itemNum ) { ... itemInfo_t *itemInfo; ... memset( itemInfo, 0, sizeof( &itemInfo ) ); Стр. 9 из 48 28.10.2011 14:06
  • 10. Реклама PVS-Studio - статический анализ кода на языке Си и Си++ file:///E:/PVS-Studio_detects_ru.html ... } Ошибка найдена с помощью диагностики V568: It's odd that the argument of sizeof() operator is the '&itemInfo' expression. cgame cg_weapons.c 1467. Оператор sizeof() вычисляет размер указателя, а не структуры 'itemInfo_t'. На самом деле должно быть написано "sizeof(*itemInfo)". Пример 2. Проект Wolfenstein 3D. Копирование только части матрицы. ID_INLINE mat3_t::mat3_t( float src[ 3 ][ 3 ] ) { memcpy( mat, src, sizeof( src ) ); } Ошибка найдена с помощью диагностики V511: The sizeof() operator returns size of the pointer, and not of the array, in 'sizeof(src)' expression. Splines math_matrix.h 94 Как правило, программисты ожидают, что 'sizeof(src)' вернет размер массива равного "3*3*sizeof(float)". Но согласно стандарту языка, 'src' это просто указатель, а вовсе не массив. Таким образом, матрица будет скопирована только частично. Функция 'memcpy' скопирует 4 или 8 байт (размер указателя) в зависимости от того, этот код 32-битный или 64-битный. Если хочется скопировать матрицу целиком, то можно передать в функцию ссылку на массив. Корректный вариант кода: ID_INLINE mat3_t::mat3_t( float (&src)[3][3] ) { memcpy( mat, src, sizeof( src ) ); } Пример 3. Проект FAR Manager. Очистка только части массива. struct TreeItem { int *Last; size_t LastCount; ... void Clear() { strName.Clear(); memset(Last, 0, sizeof(Last)); Depth=0; } }; Ошибка найдена с помощью диагностики V579: The memset function receives the pointer and its size as arguments. It is possibly a mistake. Inspect the third argument. far treelist.hpp 66 Скорее всего, здесь не хватает умножения на количество очищаемых элементов, и код должен был выглядеть так: "memset(Last, 0, LastCount * sizeof(Last));". Пример 4. Проект ReactOS. Некорректное вычисление длины строки. static const PCHAR Nv11Board = "NV11 (GeForce2) Board"; static const PCHAR Nv11Chip = "Chip Rev B2"; static const PCHAR Nv11Vendor = "NVidia Corporation"; BOOLEAN IsVesaBiosOk(...) Стр. 10 из 48 28.10.2011 14:06
  • 11. Реклама PVS-Studio - статический анализ кода на языке Си и Си++ file:///E:/PVS-Studio_detects_ru.html { ... if (!(strncmp(Vendor, Nv11Vendor, sizeof(Nv11Vendor))) && !(strncmp(Product, Nv11Board, sizeof(Nv11Board))) && !(strncmp(Revision, Nv11Chip, sizeof(Nv11Chip))) && (OemRevision == 0x311)) ... } Ошибка найдена с помощью диагностики V579: The strncmp function receives the pointer and its size as arguments. It is possibly a mistake. Inspect the third argument. vga vbe.c 57 Имеющиеся в коде вызовы функции 'strncmp' сравнивают только несколько первых символов, а не строки целиком. Ошибка в том, что для вычисления длины строк используется совершенно неуместный здесь оператор sizeof(). Оператор sizeof() вычисляет размер указателя, а вовсе не количество байт в строке. Самое неприятное и коварное с этой ошибкой в том, что этот код почти работает. В 99% случаев сравнение по первым нескольким символам бывает достаточно. Зато 1% может подарить массу удовольствий и долгую отладку. Пример 5. Проект VirtualDub. Выход за рамки массива (явный индекс). struct ConvoluteFilterData { long m[9]; long bias; void *dyna_func; DWORD dyna_size; DWORD dyna_old_protect; BOOL fClip; }; static unsigned long __fastcall do_conv( unsigned long *data, const ConvoluteFilterData *cfd, long sflags, long pit) { long rt0=cfd->m[9], gt0=cfd->m[9], bt0=cfd->m[9]; ... } Ошибка найдена с помощью диагностики V557: Array overrun is possible. The '9' index is pointing beyond array bound. VirtualDub f_convolute.cpp 73 Одна из самых простых ошибок, приводящих к выходу за границы массива. Явно используется индекс 9, хотя индекс последнего элемента равен 8. Возможно, автор на мгновение забыл, что в Си/Си++ элементы массивов нумеруются с нуля, а не с единицы. Такое случается, когда приходится переключаться между различными языками программирования. Пример 6. Проект CPU Identifying Tool. Выход за рамки массива (индекс в макросе). #define FINDBUFFLEN 64 // Max buffer find/replace size ... int WINAPI Sticky (...) { ... static char findWhat[FINDBUFFLEN] = {'0'}; ... findWhat[FINDBUFFLEN] = '0'; ... } Стр. 11 из 48 28.10.2011 14:06
  • 12. Реклама PVS-Studio - статический анализ кода на языке Си и Си++ file:///E:/PVS-Studio_detects_ru.html Ошибка найдена с помощью диагностики V557: Array overrun is possible. The '64' index is pointing beyond array bound. stickies stickies.cpp 7947 Эта ошибочная ситуация является разновидностью предыдущей. Терминальный ноль записывается за границей массива. Корректным вариантом кода будет: "findWhat[FINDBUFFLEN - 1] = '0';". Пример 7. Проект Wolfenstein 3D. Выход за рамки массива (неверное выражение). void BotTeamAI( bot_state_t *bs ) { ... bs->teamleader[sizeof( bs->teamleader )] = '0'; ... } Ошибка найдена с помощью диагностики V557: Array overrun is possible. The 'sizeof (bs->teamleader)' index is pointing beyond array bound. game ai_team.c 548 И ещё один пример выхода за границу массива при использовании явно заданного индекса. Эти примеры показывают, что такие, на первый взгляд простые, ошибки распространены гораздо шире, чем может показаться. Терминальный ноль записывается за пределами массива 'teamleader'. Корректный вариант: bs->teamleader[sizeof( bs->teamleader ) - 1] = '0'; Пример 8. Проект Miranda IM. Копирование только части строки. typedef struct _textrangew { CHARRANGE chrg; LPWSTR lpstrText; } TEXTRANGEW; const wchar_t* Utils::extractURLFromRichEdit(...) { ... ::CopyMemory(tr.lpstrText, L"mailto:", 7); ... } Ошибка найдена с помощью диагностики V512: A call of the 'memcpy' function will lead to a buffer overflow or underflow. tabsrmm utils.cpp 1080 Если используются Unicode-строки, то один символ занимает не один байт, а 2 или 4 байта (в зависимости от используемой модели данных в компиляторе). К сожалению, про этом легко забывается, и нередко в программах можно встретить дефекты, аналогичные тому, который показан здесь. Функция 'CopyMemory' скопирует только часть строки L"mailto:", так как работает с байтами, а не с символами. Код можно исправить, используя более подходящую функцию для копирования строк или, по крайней мере, умножив число 7 на sizeof(wchar_t). Пример 9. Проект CMake. Выход за границу массива внутри цикла. static const struct { DWORD winerr; int doserr; } doserrors[] = Стр. 12 из 48 28.10.2011 14:06
  • 13. Реклама PVS-Studio - статический анализ кода на языке Си и Си++ file:///E:/PVS-Studio_detects_ru.html { ... }; static void la_dosmaperr(unsigned long e) { ... for (i = 0; i < sizeof(doserrors); i++) { if (doserrors[i].winerr == e) { errno = doserrors[i].doserr; return; } } ... } Ошибка найдена с помощью диагностики V557: Array overrun is possible. The value of 'i' index could reach 367. cmlibarchive archive_windows.c 1140, 1142 Обработчик ошибок сам содержит ошибку. Оператор sizeof() возвращает размер массива в байтах, а не количество элементов в нём. В результате, в цикле программа попытается перебирать намного больше элементов, чем должна. Корректный цикл должен выглядеть так: for (i = 0; i < sizeof(doserrors) / sizeof(*doserrors); i++) Пример 10. Проект CPU Identifying Tool. Печать строки саму в себя. char * OSDetection () { ... sprintf(szOperatingSystem, "%sversion %d.%d %s (Build %d)", szOperatingSystem, osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.szCSDVersion, osvi.dwBuildNumber & 0xFFFF); ... sprintf (szOperatingSystem, "%s%s(Build %d)", szOperatingSystem, osvi.szCSDVersion, osvi.dwBuildNumber & 0xFFFF); ... } Ошибка найдена с помощью диагностики V541: It is dangerous to print the string 'szOperatingSystem' into itself. stickies camel.cpp 572, 603 К достаточно печальным последствиям может привести попытка форматированной печати строки в саму себя. Результат работы такого кода зависит от входных данных и предсказать, что произойдет сложно. Скорее всего, результатом работы станет бессмысленная строка или возникнет Access Violation. Эту ошибку вполне можно отнести к категории "уязвимость в коде". В ряде программ, подав на вход специальные данные, можно использовать такие участки кода, чтобы привести к переполнению буфера или иным полезным злоумышленнику действиям. Пример 11. Проект FCE Ultra. Для строки выделяется памяти меньше, чем надо. Стр. 13 из 48 28.10.2011 14:06
  • 14. Реклама PVS-Studio - статический анализ кода на языке Си и Си++ file:///E:/PVS-Studio_detects_ru.html int FCEUI_SetCheat(...) { ... if((t=(char *)realloc(next->name,strlen(name+1)))) ... } Ошибка найдена с помощью диагностики V518: The 'realloc' function allocates strange amount of memory calculated by 'strlen(expr)'. Perhaps the correct variant is 'strlen(expr) + 1'. fceux cheat.cpp 609 Причиной ошибки является опечатка. Аргументом функции strlen() должен быть указатель 'name', а вовсе не выражение "name+1". В результате, функция realloc выделит на 2 байта меньше памяти, чем необходимо. Один байт потеряется из-за того, что к длине строки не прибавлена единица. Другой байт потеряется из-за того, что функция 'strlen' считает длину строки, пропустив первый символ. Пример 12. Проект Notepad++. Частичное обнуление массива. #define CONT_MAP_MAX 50 int _iContMap[CONT_MAP_MAX]; ... DockingManager::DockingManager() { ... memset(_iContMap, -1, CONT_MAP_MAX); ... } Ошибка найдена с помощью диагностики V512: A call of the memset function will lead to a buffer overflow or underflow. notepadPlus DockingManager.cpp 60 Очередная путаница с количеством элементов в массиве и его размером. Забыто умножение на sizeof(int). Мы готовы продолжать и продолжать показывать ошибки работы с массивами, найденные нами в различных программах. Но надо где-то остановиться. Пусть здесь ошибок будет 12, а то число 13 считается несчастливым. Неопределенное поведение (Undefined behavior) В начале немного теории. Неопределённое поведение (англ. undefined behaviour) — свойство некоторых языков программирования (наиболее заметно в Cи и Си++) в определённых ситуациях выдавать результат, зависящий от реализации компилятора. Другими словами, спецификация не определяет поведение языка в любых возможных ситуациях, а говорит: "при условии А результат операции Б не определён". Допускать такую ситуацию в программе считается ошибкой, даже если на некотором компиляторе программа успешно выполняется, она не будет кроссплатформенной и может отказать на другой машине в другой ОС и даже на других настройках компилятора. Точка следования (англ. Sequence point) — в программировании любая точка программы, в которой гарантируется, что все побочные эффекты предыдущих вычислений уже проявились, а побочные эффекты последующих еще отсутствуют. Подробнее про точки следования и какие ситуации неопределенного поведения с ними связаны можно прочитать здесь: http://www.viva64.com/ru/t/0065/. Стр. 14 из 48 28.10.2011 14:06
  • 15. Реклама PVS-Studio - статический анализ кода на языке Си и Си++ file:///E:/PVS-Studio_detects_ru.html Пример 1. Проект Chromium. Некорректное использование умного указателя. void AccessibleContainsAccessible(...) { ... auto_ptr<VARIANT> child_array(new VARIANT[child_count]); ... } Ошибка найдена с помощью диагностики V554: Incorrect use of auto_ptr. The memory allocated with 'new []' will be cleaned using 'delete'. interactive_ui_tests accessibility_win_browsertest.cc 171 Это пример демонстрирует, когда использование умного указателя может привести к неопределенному поведению. Проявить себя это может повреждением кучи, аварийным завершением программы, неполному разрушению объектов или любым другим образом. Ошибка заключается в том, что память выделяется с помощью оператора new [], а освобождается в деструкторе класса 'auto_ptr' с помощью оператора delete: ~auto_ptr() { delete _Myptr; } Чтобы исправить ситуации, необходимо использовать более подходящий класс, например boost::scoped_array. Пример 2. Проект IPP Samples. Классический Undefined behavior. template<typename T, Ipp32s size> void HadamardFwdFast(...) { Ipp32s *pTemp; ... for(j=0;j<4;j++) { a[0] = pTemp[0*4] + pTemp[1*4]; a[1] = pTemp[0*4] - pTemp[1*4]; a[2] = pTemp[2*4] + pTemp[3*4]; a[3] = pTemp[2*4] - pTemp[3*4]; pTemp = pTemp++; ... } ... } Ошибка найдена с помощью диагностики V567: Undefined behavior. The 'pTemp' variable is modified while being used twice between sequence points. me umc_me_cost_func.h 168 Это классический пример неопределенного поведения программы. Именно такую конструкцию используют для демонстрации Undefined behavior во многих статьях. Неизвестно, увеличится pTemp на единицу или нет. Два действия по изменению значения pTemp находятся в одной точке следования. Это значит, что компилятор может создать следующий псевдокод: pTemp = pTemp + 1; pTemp = pTemp; А может, создать другой вариант кода: TMP = pTemp; pTemp = pTemp + 1; Стр. 15 из 48 28.10.2011 14:06
  • 16. Реклама PVS-Studio - статический анализ кода на языке Си и Си++ file:///E:/PVS-Studio_detects_ru.html pTemp = TMP; Какой именно код будет создан, зависит от компилятора и ключей оптимизации. Пример 3. Проект Fennec Media Project. Сложное выражение. uint32 CUnBitArrayOld::DecodeValueRiceUnsigned(uint32 k) { ... while (!(m_pBitArray[m_nCurrentBitIndex >> 5] & Powers_of_Two_Reversed[m_nCurrentBitIndex++ & 31])) {} ... } Ошибка найдена с помощью диагностики V567: Undefined behavior. The 'm_nCurrentBitIndex' variable is modified while being used twice at single sequence point. MACLib unbitarrayold.cpp 78 Между двумя использованиями переменной m_nCurrentBitIndex нет точек следования. Это значит, что стандартом не определено, в какой момент эта переменная увеличится. Соответственно, в зависимости от компилятора и ключей оптимизации, этот код может работать по-разному. Пример 4. Проект Miranda IM. Сложное выражение. short ezxml_internal_dtd(ezxml_root_t root, char *s, size_t len) { ... while (*(n = ++s + strspn(s, EZXML_WS)) && *n != '>') { ... } Ошибка найдена с помощью диагностики V567: Undefined behavior. The 's' variable is modified while being used twice between sequence points.msne zxml.c 371 Здесь используется префиксный инкремент переменной. Но это ничего не значит. Нет никакой гарантии, что переменная 's' будет увеличена перед вызовом функции strspn(). Ошибки, связанные с приоритетом операций. Для легкости понимания примеров освежим в памяти таблицу приоритетов операций. Стр. 16 из 48 28.10.2011 14:06
  • 17. Реклама PVS-Studio - статический анализ кода на языке Си и Си++ file:///E:/PVS-Studio_detects_ru.html Рисунок 7 - Приоритет операций языка Си/Си++ Пример 1. Проект MySQL. Приоритет операции ! и &. int ha_innobase::create(...) { ... if (srv_file_per_table && !mysqld_embedded && (!create_info->options & HA_LEX_CREATE_TMP_TABLE)) { ... } Ошибка найдена с помощью диагностики V564: The '&' operator is applied to bool type value. You've probably forgotten to include parentheses or intended to use the '&&' operator. innobase ha_innodb.cc 6789 Стр. 17 из 48 28.10.2011 14:06
  • 18. Реклама PVS-Studio - статический анализ кода на языке Си и Си++ file:///E:/PVS-Studio_detects_ru.html По замыслу программиста, часть выражения должна проверить, что определенный бит в переменной 'create_info->options' равен нулю. Однако, приоритет операции '!' выше, чем операции '&'. И выражение работает так: ((!create_info->options) & HA_LEX_CREATE_TMP_TABLE) Чтобы код работал правильно, необходимо использовать дополнительные скобки: (!(create_info->options & HA_LEX_CREATE_TMP_TABLE)) Или, что на наш взгляд более красиво, написать так: ((create_info->options & HA_LEX_CREATE_TMP_TABLE) == 0) Пример 2. Проект Emule. Приоритет операции * и ++. STDMETHODIMP CCustomAutoComplete::Next(..., ULONG *pceltFetched) { ... if (pceltFetched != NULL) *pceltFetched++; ... } Ошибка найдена с помощью диагностики V532: Consider inspecting the statement of '*pointer++' pattern. Probably meant: '(*pointer)++'. emule customautocomplete.cpp 277 Если указатель 'pceltFetched' не нулевой, функция должна увеличивать переменную типа ULONG, на которую этот указатель указывает. Ошибка в том, что в приоритет операции '++' выше, чем приоритет операции '*' (разыменования указателя). Строка "*pceltFetched++;" эквивалентна следующим действиям: TMP = pceltFetched + 1; *pceltFetched; pceltFetched = TMP; Фактически, здесь просто увеличивается значение указателя. Чтобы код стал корректен, необходимо добавить скобки: "(*pceltFetched)++;". Пример 3. Проект Chromium. Приоритет операции & и !=. #define FILE_ATTRIBUTE_DIRECTORY 0x00000010 bool GetPlatformFileInfo(PlatformFile file, PlatformFileInfo* info) { ... info->is_directory = file_info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY != 0; ... } Ошибка найдена с помощью диагностики V564: The '&' operator is applied to bool type value. You've probably forgotten to include parentheses or intended to use the '&&' operator. base platform_file_win.cc 216 Очень легко забыть, что приоритет операции '!=' выше, чем операции '&'. Так произошло и здесь. В результате получается выражение: info->is_directory = file_info.dwFileAttributes & (0x00000010 != 0); Упростим выражение: Стр. 18 из 48 28.10.2011 14:06
  • 19. Реклама PVS-Studio - статический анализ кода на языке Си и Си++ file:///E:/PVS-Studio_detects_ru.html info->is_directory = file_info.dwFileAttributes & (true); Ещё раз упростим выражение: info->is_directory = file_info.dwFileAttributes & 1; Получается, что вместо пятого бита, протестировали первый бит. Чтобы исправить ситуацию, требуются вставить дополнительные скобки. Пример 4. Проект BCmenu. Путаница с IF и ELSE. void BCMenu::InsertSpaces(void) { if(IsLunaMenuStyle()) if(!xp_space_accelerators) return; else if(!original_space_accelerators) return; ... } Ошибка найдена с помощью диагностики V563: It is possible that this 'else' branch must apply to the previous 'if' statement. fire bcmenu.cpp 1853 Здесь ошибка не с приоритетом операций, но родственная ей. Не учтено, что ветка 'else' относится к ближайшему оператору 'if'. Видно, что код оформлен исходя из того, как будто он работает так: if(IsLunaMenuStyle()) { if(!xp_space_accelerators) return; } else { if(!original_space_accelerators) return; } Но на самом деле он эквивалентен следующей конструкции: if(IsLunaMenuStyle()) { if(!xp_space_accelerators) { return; } else { if(!original_space_accelerators) return; } } Пример 5. Проект IPP Samples. Приоритет операции ?: и |. vm_file* vm_file_fopen(...) { ... mds[3] = FILE_ATTRIBUTE_NORMAL | (islog == 0) ? 0 : FILE_FLAG_NO_BUFFERING; ... } Ошибка найдена с помощью диагностики V502: Perhaps the '?:' operator works in a different way than it was expected. The '?:' operator has a lower priority than the '|' operator. vm vm_file_win.c 393 В зависимости от значения переменной 'islog', выражение должно было быть равно "FILE_ATTRIBUTE_NORMAL" или "FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING". Но этого не происходит. Приоритет операции '?:' ниже, чем операции '|'. В результате код работает так: Стр. 19 из 48 28.10.2011 14:06
  • 20. Реклама PVS-Studio - статический анализ кода на языке Си и Си++ file:///E:/PVS-Studio_detects_ru.html mds[3] = (FILE_ATTRIBUTE_NORMAL | (islog == 0)) ? 0 : FILE_FLAG_NO_BUFFERING; Упростим выражение: mds[3] = (0x00000080 | ...) ? 0 : FILE_FLAG_NO_BUFFERING; Так как FILE_ATTRIBUTE_NORMAL равняется 0x00000080, то условие всегда истинно. Это означает, что в mds[3] всегда будет записываться 0. Пример 6. Проект Newton Game Dynamics. Приоритет операции ?: и *. dgInt32 CalculateConvexShapeIntersection (...) { ... den = dgFloat32 (1.0e-24f) * (den > dgFloat32 (0.0f)) ? dgFloat32 (1.0f) : dgFloat32 (-1.0f); ... } Ошибка найдена с помощью диагностики V502: Perhaps the '?:' operator works in a different way than it was expected. The '?:' operator has a lower priority than the '*' operator. physics dgminkowskiconv.cpp 1061 В этом коде ошибка вновь связана с низким приоритетом операции '?:'. Условием для оператора '?:' является бессмысленное подвыражение "dgFloat32 (1.0e-24f) * (den > dgFloat32 (0.0f))". Исправить ситуацию можно, используя круглые скобки. Кстати, программисты часто забывают о коварстве оператора '?:'. Предлагаю заметку на эту тему: "Как уменьшить вероятность ошибки на этапе написания кода. Заметка N2". Ошибки форматированного вывода Примеры этих ошибок однообразны и скучны, поэтому рассмотрим совсем немного примеров. Их суть в том, что функции с переменным количеством аргументов принимают фактические аргументы, несовместимые со строкой, задающей формат. Любой программист, использующий такие функции, как printf(), хорошо знаком с данной разновидностью ошибок. Пример 1. Проект ReactOS. Некорректная печать символа типа WCHAR. static void REGPROC_unescape_string(WCHAR* str) { ... default: fprintf(stderr, "Warning! Unrecognized escape sequence: %c'n", str[str_idx]); ... } Ошибка найдена с помощью диагностики V576: Incorrect format. Consider checking the third actual argument of the 'fprintf' function. The char type argument is expected. regedit regproc.c 293 Функция fprinf() должна распечатать символ типа char. Но третьим аргументов является символ типа WCHAR. Пользователю будет выдано некорректно сформированное сообщение. Чтобы код стал корректен, в строке, задающей формат, следует заменить '%c' на '%C'. Стр. 20 из 48 28.10.2011 14:06
  • 21. Реклама PVS-Studio - статический анализ кода на языке Си и Си++ file:///E:/PVS-Studio_detects_ru.html Пример 2. Проект Intel AMT SDK. Пропущенный символ '%'. void addAttribute(...) { ... int index = _snprintf(temp, 1023, "%02x%02x:%02x%02x:%02x%02x:%02x%02x:" "%02x%02x:02x%02x:%02x%02x:%02x%02x", value[0],value[1],value[2],value[3],value[4], value[5],value[6],value[7],value[8], value[9],value[10],value[11],value[12], value[13],value[14],value[15]); ... } Ошибка найдена с помощью диагностики V576: Incorrect format. A different number of actual arguments is expected while calling '_snprintf' function. Expected: 18. Present: 19. mod_pvs mod_pvs.cpp 308 На взгляд найти здесь ошибку очень непросто. Однако, статический анализатор PVS-Studio неутомим и замечает, что функция принимает больше фактических аргументов, чем задано в строке форматирования. Дело в том, что в одном месте пропущен символ '%'. Выделим этот фрагмент: "%02x%02x:[HERE]02x%02x:%02x%02x:%02x%02x", Пример 3. Проект Intel AMT SDK. Неиспользуемый аргумент. bool GetUserValues(...) { ... printf("Error: illegal value. Aborting.n", tmp); return false; } Ошибка найдена с помощью диагностики V576: Incorrect format. A different number of actual arguments is expected while calling 'printf' function. Expected: 1. Present: 2. RemoteControlSample remotecontrolsample.cpp 792 Ошибка в том, что переменная 'tmp' никак не используется при выводе информационного сообщения. Пример 4. Проект G3D Content Pak. Печать бессмысленных данных. class Matrix3 { ... inline float* operator[] (int iRow) { ... }; void AnyVal::serialize(G3D::TextOutput& t) const { ... const Matrix3& m = *(Matrix3*)m_value; ... t.printf("%10.5f, %10.5f, %10.5f,n %10.5f, %10.5f, %10.5f,n %10.5f, %10.5f, %10.5f)", m[0, 0], m[0, 1], m[0, 2], m[1, 0], m[1, 1], m[1, 2], m[2, 0], m[2, 1], m[2, 2]); ... } Стр. 21 из 48 28.10.2011 14:06
  • 22. Реклама PVS-Studio - статический анализ кода на языке Си и Си++ file:///E:/PVS-Studio_detects_ru.html Ошибка найдена с помощью диагностики V520: The comma operator ',' in array index expression '[0, 0]'. graphics3D anyval.cpp 275 Программа вместо матрицы распечатает бессмысленные значения. Такой код можно написать, если работать с разными языками программирования и забыть на время, как получать доступ к элементу двухмерного массива в языке Си. Рассмотрим, как работает выражение 'm[0, 1]'. Вначале вычисляется выражение "0, 1". Результатом такого выражения является 1. Затем вызывается функция 'operator[]' в классе Matrix3. Функция принимает фактический аргумент 1 и вернет указатель на первую строку в матрице. Именно значение этого указателя и будет распечатано функцией 'printf()', хотя она ожидает значение типа float. Корректный вариант: t.printf("%10.5f, %10.5f, %10.5f,n %10.5f, %10.5f, %10.5f,n %10.5f, %10.5f, %10.5f)", m[0][0], m[0][1], m[0][2], m[1][0], m[1][1], m[1][2], m[2][0], m[2][1], m[2][2]); Примеры выявленных опечаток в коде Огромное количество ошибок при программировании допускается из-за опечаток. Большинство этих ошибок быстро выявляются на самых ранних этапах тестирования. Однако, некоторые такие ошибки надолго остаются в коде программы, доставляя беспокойство программистам и неудобства пользователям. Количество таких ошибок можно существенно сократить, используя статический анализатор PVS-Studio. Анализатор найдет их еще до начала тестирования, что существенно сократит цену нахождения и устранения дефектов. Пример 1. Проект Miranda IM. Присваивание внутри IF. void CIcqProto::handleUserOffline(BYTE *buf, WORD wLen) { ... else if (wTLVType = 0x29 && wTLVLen == sizeof(DWORD)) ... } Ошибка найдена с помощью диагностики V560: A part of conditional expression is always true: 0x29. icqoscar8 fam_03buddy.cpp 632 Из-за опечатки, внутри условия оператора 'if' происходит присваивание. Корректное условие: "if (wTLVType == 0x29 && wTLVLen == sizeof(DWORD))". Пример 2. Проект ReactOS. Ошибка присваивания. BOOL WINAPI GetMenuItemInfoA(...) { ... mii->cch = mii->cch; ... } Стр. 22 из 48 28.10.2011 14:06
  • 23. Реклама PVS-Studio - статический анализ кода на языке Си и Си++ file:///E:/PVS-Studio_detects_ru.html Ошибка найдена с помощью диагностики V570: The 'mii->cch' variable is assigned to itself. user32 menu.c 4347 Значение переменной присваивается само себе. Очевидно, планировалось написать так: "mii->cch = miiW->cch;". Пример 3. Проект Clang. Опечатка в названии объекта. static Value *SimplifyICmpInst(...) { ... case Instruction::Shl: { bool NUW = LBO->hasNoUnsignedWrap() && LBO->hasNoUnsignedWrap(); bool NSW = LBO->hasNoSignedWrap() && RBO->hasNoSignedWrap(); ... } Ошибка найдена с помощью диагностики V501: There are identical sub-expressions 'LBO->hasNoUnsignedWrap ()' to the left and to the right of the '&&' operator. LLVMAnalysis instructionsimplify.cpp 1891 Имеется опечатка при использовании переменных с похожими именами. В первой строке надо использовать как переменную LBO, так и RBO. Исправленный вариант кода: bool NUW = LBO->hasNoUnsignedWrap() && RBO->hasNoUnsignedWrap(); Пример 4. Проект Notepad++. Неправильная проверка состояния. bool _isPointXValid; bool _isPointYValid; ... bool isPointValid() { return _isPointXValid && _isPointXValid; }; Ошибка найдена с помощью диагностики V501: There are identical sub-expressions to the left and to the right of the '&&' operator. _isPointXValid && _isPointXValid Дважды используется имя '_isPointXValid'. На самом деле, функция должна вернуть: "_isPointXValid && _isPointYValid". Пример 5. Проект StrongDC++. Неудачная проверка наличия rn. static void getContentLengthAndHeaderLength(...) { ... while(line[linelen] != 'r' && line[linelen] != 'r') ... } Ошибка найдена с помощью диагностики V501: There are identical sub-expressions 'line [linelen] != 'r'' to the left and to the right of the '&&' operator. miniupnpc miniupnpc.c 153 Из-за опечатки дважды проверяем наличие символа 'r'. На самом деле еще должно проверяться наличие символа 'n'. Пример 6. Проект G3D Content Pak. Не там поставлена круглая закрывающаяся скобка. Стр. 23 из 48 28.10.2011 14:06
  • 24. Реклама PVS-Studio - статический анализ кода на языке Си и Си++ file:///E:/PVS-Studio_detects_ru.html bool Matrix4::operator==(const Matrix4& other) const { if (memcmp(this, &other, sizeof(Matrix4) == 0)) { return true; } ... } Ошибка найдена с помощью диагностики V575: The 'memcmp' function processes '0' elements. Inspect the 'third' argument. graphics3D matrix4.cpp 269 Одна круглая скобка закрывается не там, где необходимо. Получается, что размер сравниваемой области памяти вычисляется выражением "sizeof(Matrix4) == 0". Это выражение всегда даёт в результате значение 'false'. Затем 'false' превращается в целочисленное значение, равное 0. Корректный код: if (memcmp(this, &other, sizeof(Matrix4)) == 0) { Пример 7. Проект QT. Ошибка копирования членов структуры. PassRefPtr<Structure> Structure::getterSetterTransition(Structure* structure) { ... transition->m_propertyStorageCapacity = structure->m_propertyStorageCapacity; transition->m_hasGetterSetterProperties = transition->m_hasGetterSetterProperties; transition->m_hasNonEnumerableProperties = structure->m_hasNonEnumerableProperties; transition->m_specificFunctionThrashCount = structure->m_specificFunctionThrashCount; ... } Ошибка найдена с помощью диагностики V570: The 'transition->m_hasGetterSetterProperties' variable is assigned to itself. QtScript structure.cpp 512 Рассматривая подобный код, очень сложно заметить ошибку. Однако, она здесь есть. Поле 'm_hasGetterSetterProperties' копируется само в себя. Корректный код должен выглядеть так: transition->m_hasGetterSetterProperties = structure->m_hasGetterSetterProperties; Пример 8. Проект Apache HTTP Server. Лишний оператор sizeof. PSECURITY_ATTRIBUTES GetNullACL(void) { PSECURITY_ATTRIBUTES sa; sa = (PSECURITY_ATTRIBUTES) LocalAlloc(LPTR, sizeof(SECURITY_ATTRIBUTES)); sa->nLength = sizeof(sizeof(SECURITY_ATTRIBUTES)); ... } Ошибка найдена с помощью диагностики V568: It's odd that the argument of sizeof() operator is the 'sizeof (SECURITY_ATTRIBUTES)' expression. libhttpd util_win32.c 115 В поле 'nLength' должен был записан размер структуры 'SECURITY_ATTRIBUTES'. В коде допущена опечатка. Оператор 'sizeof' здесь используется два раза. Как результат, в поле 'nLength' записывается размер, которыё имеет тип 'size_t'. Корректный код: Стр. 24 из 48 28.10.2011 14:06
  • 25. Реклама PVS-Studio - статический анализ кода на языке Си и Си++ file:///E:/PVS-Studio_detects_ru.html sa->nLength = sizeof(SECURITY_ATTRIBUTES); Пример 9. Проект FCE Ultra. Двойное объявление переменной. int iNesSaveAs(char* name) { ... fp = fopen(name,"wb"); int x = 0; if (!fp) int x = 1; ... } Ошибка найдена с помощью диагностики V561: It's probably better to assign value to 'x' variable than to declare it anew. Previous daclaration: ines.cpp, line 960. fceuxines.cpp 962 Переменная 'x' должна хранить информацию, удалось ли открыть файл или нет. Из-за опечатки, вместо присваивания переменной единицы создается и инициализируется новая переменная с именем 'x'. Корректный код, должен был быть таким: if (!fp) x = 1; Пример 10. Проект Notepad++. Использование оператора &&, вместо &. TCHAR GetASCII(WPARAM wParam, LPARAM lParam) { ... result=ToAscii(wParam, (lParam >> 16) && 0xff, keys,&dwReturnedValue,0); ... } Ошибка найдена с помощью диагностики V560: A part of conditional expression is always true: 0xff. notepadPlus babygrid.cpp 694 Выражение "(lParam >> 16) && 0xff" не имеет никакого практического смысла и всегда равно значению 1 (true). Здесь опечатка заключается в том, что используется оператор '&&', хотя должен был использоваться оператор '&'. Пример 11. Проект WinDjView. Недописанное условие. inline bool IsValidChar(int c) { return c == 0x9 || 0xA || c == 0xD || c >= 0x20 && c <= 0xD7FF || c >= 0xE000 && c <= 0xFFFD || c >= 0x10000 && c <= 0x10FFFF; } Ошибка найдена с помощью диагностики V560: A part of conditional expression is always true: 0xA. WinDjView xmlparser.cpp 45 False Функция IsValidChar всегда возвращает значение 'true'. Из-за опечатки, в одном месте пропущено сравнение: "... || 0xA || ...". Пример 12. Проект Fennec Media Project. Лишняя точка с запятой. int settings_default(void) { Стр. 25 из 48 28.10.2011 14:06
  • 26. Реклама PVS-Studio - статический анализ кода на языке Си и Си++ file:///E:/PVS-Studio_detects_ru.html ... for(i=0; i<16; i++); for(j=0; j<32; j++) { settings.conversion.equalizer_bands.boost[i][j] = 0.0; settings.conversion.equalizer_bands.preamp[i] = 0.0; } } Ошибка найдена с помощью диагностики V529: Odd semicolon ';' after 'for' operator. settings.c 483 Про то, как опасна лишняя точка с запятой ';' знают все программисты на Си и Си++. К сожалению, это знание не мешает делать подобные опечатки. После первого оператора 'for' стоит лишняя точка с запятой, что делает этот фрагмент программы неработоспособным. Пример 13. Проект QT. Забытый оператор break. int QCleanlooksStyle::pixelMetric(...) { ... case PM_SpinBoxFrameWidth: ret = 3; break; case PM_MenuBarItemSpacing: ret = 6; case PM_MenuBarHMargin: ret = 0; break; ... } Ошибка найдена с помощью диагностики: V519: The 'ret' variable is assigned values twice successively. Perhaps this is a mistake. Check lines: 3765, 3767. QtGui qcleanlooksstyle.cpp 3767 Классическая ошибка - пропущен 'break' внутри оператора 'switch'. Думаю, комментарии здесь излишни. Пример 14. Проект Miranda IM. Присваивание вместо сравнения. int FindItem(...) { ... int ret; ret=FindItem(hwnd,dat,hItem, (struct ClcContact ** )&z, (struct ClcGroup ** )&isv,NULL); if (ret=0) {return (0);} ... } Ошибка найдена с помощью диагностики V559: Suspicious assignment inside the condition expression of 'if' operator: ret = 0. clist_mw clcidents.c 179 Опечатка находится внутри условия оператора 'if'. Вместо '==' написано просто '='. Функция некорректно обработает ситуацию, когда некий элемент не будет найден. Пример 15. Проект IPP Samples. Некорректный индекс. struct AVS_MB_INFO { ... Стр. 26 из 48 28.10.2011 14:06
  • 27. Реклама PVS-Studio - статический анализ кода на языке Си и Си++ file:///E:/PVS-Studio_detects_ru.html Ipp8u refIdx[AVS_DIRECTIONS][4]; ... }; void AVSCompressor::GetRefIndiciesBSlice(void){ ... if (m_pMbInfo->predType[0] & predType) { m_refIdx[iRefNum] = m_pMbInfo->refIdx[dir][0]; iRefNum += 1; } if (m_pMbInfo->predType[1] & predType) { m_refIdx[iRefNum] = m_pMbInfo->refIdx[dir][1]; iRefNum += 1; } if (m_pMbInfo->predType[2] & predType) { m_refIdx[iRefNum] = m_pMbInfo->refIdx[dir][2]; iRefNum += 1; } if (m_pMbInfo->predType[3] & predType) { m_refIdx[iRefNum] = m_pMbInfo->refIdx[dir][30]; iRefNum += 1; } ... } Ошибка найдена с помощью диагностики V557: Array overrun is possible. The '30' index is pointing beyond array bound. avs_enc umc_avs_enc_compressor_enc_b.cpp 495 Обратите внимание вот на этот фрагмент: "m_pMbInfo->refIdx[dir][30]". Из-за опечатки вместо индекса 3 написано число 30. Кстати, этот пример хорошо показывает относительность разделения в статье ошибок по типам. Эту ошибку вполне можно отнести к разделу "Ошибки работы с массивами и строками". Деление условно и сделано, чтобы показать разнородность ошибок, которые может найти анализатор PVS-Studio. Пример 16. Проект ReactOS. Опечатка в макросе. #define SWAP(a,b,c) c = a; a = b; a = c Ошибка найдена с помощью диагностики V519: The 'v2' variable is assigned values twice successively. Perhaps this is a mistake. Check lines: 343, 343. win32k gradient.c 343 Весьма забавная опечатка в макросе, который предназначен для обмена значений в двух переменных. Присмотритесь к коду и помёте в чем дело. Корректный вариант должен был выглядеть так: #define SWAP(a,b,c) c = a; a = b; b = c В этот раз до пункта под номером 13 закончить раздел не получилось. Уж очень много в программах ошибок связано именно с опечатками. Гораздо больше, чем думают программисты. Этот раздел можно продолжить и дальше. В нашей коллекции ещё много забавных примеров. Но мы нашли в себе силы всё-таки остановиться на 16 примерах. Стр. 27 из 48 28.10.2011 14:06
  • 28. Реклама PVS-Studio - статический анализ кода на языке Си и Си++ file:///E:/PVS-Studio_detects_ru.html Неверное использование базовых функций и классов Пример 1. Проект Fennec Media Project. Отсутствие двух терминальных нулей. int JoiningProc(HWND hwnd,UINT uMsg, WPARAM wParam,LPARAM lParam) { ... OPENFILENAME lofn; memset(&lofn, 0, sizeof(lofn)); ... lofn.lpstrFilter = uni("All Files (*.*)0*.*"); ... } Ошибка найдена с помощью диагностики V540: Member 'lpstrFilter' should point to string terminated by two 0 characters. base windows.c 5309 В Windows API есть структуры, в которых указатели на строки должны заканчиваться двойным нулем. Именно на такую строку и указывает член 'lpstrFilter' в структуре OPENFILENAME. Описание 'lpstrFilter' в MSDN: LPCTSTR A buffer containing pairs of null-terminated filter strings. The last string in the buffer must be terminated by two NULL characters. Если забыть написать в конце дополнительный ноль, то диалог работы с файлами в поле фильтров можем содержать мусор. Исправленный код: lofn.lpstrFilter = uni("All Files (*.*)0*.*0"); Пример 2. Проект TortoiseSVN. Неверное использование функции 'remove'. STDMETHODIMP CShellExt::Initialize(....) { ... ignoredprops = UTF8ToWide(st.c_str()); // remove all escape chars ('') std::remove(ignoredprops.begin(), ignoredprops.end(), ''); break; ... } Ошибка найдена с помощью диагностики V530: The return value of function 'remove' is required to be utilized. contextmenu.cpp 442 Функция std::remove не удаляет элементы из контейнера. Она только сдвигает элементы и возвращает итератор на начало мусора. Пусть мы имеем контейнер vector<int>, содержащий элементы 1,2,3,1,2,3,1,2,3. Если выполнить код "remove( v.begin(), v.end(), 2 )", то контейнер будет содержать элементы 1,3,1,3,X,X,X, где X - некий мусор. При этом функция вернет итератор на первый мусорный элемент, и если мы хотим удалить эти мусорные элементы, то должны написать код: "v.erase(remove(v.begin(), v.end(), 2), v.end())". Пример 3. Проект TortoiseSVN. Использование функции 'empty' вместо 'clear'. CMailMsg& CMailMsg::SetFrom(string sAddress, string sName) Стр. 28 из 48 28.10.2011 14:06