PVS-Studio признаётся в любви к Linux
Я и мои коллеги очень долго отказывались обсуждать тему разработки PVS-Studio для операционной системы Linux и UNIX мира в целом. Дело не в каких-то личных пристрастиях или технических сложностях. Всё проще — это холодный, прагматический подход к развитию продукта.
Мы — маленькая компания, которая существует исключительно за счёт продажи программного продукта PVS-Studio. Мы не получаем гранты или какую-то иную поддержку от государства или больших компаний — всё это накладывает большую ответственность за выбор направления развития.
Сейчас мы накопили новых сил, собрались с духом и начинаем новую для нас тему освоения Linux. Да, да, это свершилось. Мы решились начать работы в этом направлении. Надеюсь, с этим у нас получится лучше, чем с CppCat.
PVS-Studio for Windows
Вначале кратко напомню, что сейчас представляет собой PVS-Studio, и что он умеет на данный момент. Если Вы уже читали наши статьи, то можете пропустить этот раздел.
PVS-Studio — это инструмент для выявления ошибок в исходном коде программ, написанных на языках С, C++ и C#. Анализатор до настоящего момента был ориентирован на разработчиков, использующих среду Visual Studio. Поддерживаемые языки и диалекты:
- Visual Studio 2015: C, C++, C++/CLI, C++/CX (WinRT), C#
- Visual Studio 2013: C, C++, C++/CLI, C++/CX (WinRT), C#
- Visual Studio 2012: C, C++, C++/CLI, C++/CX (WinRT), C#
- Visual Studio 2010: C, C++, C++/CLI, C#
- MinGW (частично): C, C++
Основные особенности PVS-Studio:
- Автоматический анализ файлов после их перекомпиляции в Visual Studio.
- Сохранение и загрузка результатов анализа: можно ночью проверить код, сохранить результаты, а утром загрузить их и смотреть.
- Запуск из командной строки для проверки всего решения: позволяет интегрировать PVS-Studio в ночные сборки, чтобы утром у всех был свежий лог.
- Mark as False Alarm — разметка в коде, чтобы не ругаться конкретной диагностикой в конкретном фрагменте файла.
- Mass Suppression — подавить все старые сообщения, чтобы анализатор выдавал 0 срабатываний. К ним всегда можно вернуться позже. Удобное внедрение. Ошибки только в новом коде.
- Использование относительных путей в файлах отчета для возможности переноса отчета на другую машину.
- CLMonitoring — проверка проектов, у которых нет файлов Visual Studio (.sln/.vcxproj); если вам не хватит функциональности CLMonitoring, то вы можете интегрировать PVS-Studio в любую Makefile-based систему сборки вручную.
- Хорошая масштабируемость: анализатор может загрузить все ядра процессора. Дополнительно можно использовать совместно с IncrediBuild.
Подробнее познакомиться с анализатором, а также скачать его можно на странице продукта PVS-Studio. Напоследок приведу сводную таблицу основных диагностических возможностей PVS-Studio. В таблицу включены не все диагностики, так как некоторые из них сложно классифицировать. Это не помешает составить общее впечатление, а подробно с имеющимися диагностиками можно познакомиться здесь.
Таблица 1 — Возможности PVS-Studio. Нажмите на рисунок для его увеличения.
PVS-Studio for Linux
Теперь собственно поговорим о том, ради чего многие начали читать эту статью: о поддержке Linux.
Эта задача не так проста, как может казаться на первый взгляд. Скомпилировать исполняемый модуль под Linux и что-то с его помощью проверить — задача нехитрая. Мы давно с ней справились. Ещё год назад мы писали статью об эксперименте про проверку Vim. Однако, это только маленькая часть всего объёма работ. Программисты забывают, что собрать исполняемый модуль и создать программный продукт — это далеко не одно и тоже.
Мы планируем поддержать GCC и Clang. Мы начали с GCC, а к Clang мы вернемся позднее. Расскажу о задачах, которые сейчас стоят перед нами.
1. Более полная поддержка GCC и Clang
Мне иногда кажется, что разработчикам компиляторов скучно, и они придумывают различные способы сделать себе жизнь сложнее, а заодно и разработчикам, реализующих подсветку кода, статический анализ и так далее. Другим способом я не могу объяснить зачем, например, понадобилось вводить Conditionals with Omitted Operands. Конечно, круто, что можно сократить тернарный оператор до: z = x?: y;. На мой взгляд, без этого совершенно спокойно можно обойтись и жить счастливой жизнью.
Многих удивляет, почему надо заморачиваться с различными документированными и недокументированными расширениями компилятора. Кажется, достаточно анализировать С++, соответствующий стандарту и не обращать внимание на расширения, так как они используются крайне редко. К сожалению, это не так, и расширениям приходится уделять много времени.
Не важно, часто или нет встречаются в программе нестандартные сущности. В любой серьезной программе встретятся заголовочные файлы, содержащие какое-то из расширений. В результате это запутывает парсер в анализаторе, и он не может полноценно обработать множество *.cpp файлов, в которые включён этот злосчастный *.h файл. Конечно, в анализаторе PVS-Studio встроены механизмы, которые пытаются компенсировать ошибку разбора кода и продолжить анализ. К сожалению, этот механизм не всегда помогает. В результате могут возникать странные ложные срабатывания или наоборот, из анализа будет исключен фрагмент кода (до конца функции или класса, а то и всего файла).
Более того, всякие «хитрые» штучки любят использовать в системных заголовочных файлах. Так что на практике нарваться на какое-то расширение очень даже легко.
Если кому-то интересно, о чем всё-таки идёт речь, могу предложить взглянуть, например, на:
- GCC. Extensions to the C Language Family
- GCC. Extensions to the C++ Language
И это только документированные расширения. По опыту работы с Visual С++, мы ещё ожидаем наличие подлянок в форме недокументированных расширений.
Поскольку мы используем собственный парсер (развитие ныне забытой и заброшенной библиотеки OpenC++), то мы должны поддержать различные расширения.
Впрочем, используй мы какой-то другой парсер, это не сильно бы нам помогло. Например, если мы перепишем анализатор, взяв за основу Clang, нам все равно придётся самостоятельно сражаться с расширениями GCC, Visual C++.
2. Новая система регрессивных тестов в Linux
Разрабатывая PVS-Studio, мы используем семь методик тестирования:
- Статический анализ кода на машинах разработчиков. У всех разработчиков установлен PVS-Studio. Новый или изменённый код сразу проверяется с помощью механизма инкрементального анализа. Проверяется C++ и С# код.
- Статический анализ кода при ночных сборках. Если предупреждение не было замечено, то оно выявится на этапе ночной сборки на сервере. PVS-Studio проверяет C# и C++ код. Помимо этого, мы дополнительно используем Clang для проверки C++ кода. Одно время для C# кода также дополнительно применялся FxCop. В течение года он так ни разу ничего не нашел полезного, и мы отказались от его использования. А вот Clang пару раз находил ошибки, которые не замечал PVS-Studio, и мы сочли рациональным продолжать его использовать.
- Юнит-тесты уровня классов, методов, функций. Не очень развитая система, так как многие моменты сложно тестировать из-за необходимости подготавливать для теста большой объем входных данных. Мы больше полагаемся на высокоуровневые тесты.
- Функциональные тесты уровня специально подготовленных и размеченных файлов с ошибками.
- Функциональные тесты, подтверждающие, что мы корректно разбираем системные заголовочные файлы. Это важно, так как если в системном файле используются нестандартные расширения, то это портит проверку сразу многих проектов.
- Регрессионные тесты уровня отдельных сторонних проектов и решений (projects and solutions) — самый важный и полезный для нас вид тестирования. Для его осуществления мы регулярно проверяем 105 открытых проектов на C++ и 49 на C#. Сравнивая старые и новые результаты анализа, мы контролируем, что что-то не сломали и оттачиваем новые диагностические сообщения.
- Функциональные тесты пользовательского интерфейса. Имеется в виду тестирование расширения (plug-in), которое интегрируется в среду Visual Studio. Проверяем, что нажатие на различные кнопки и пункты меню приводит к нужным результатам.
С точки зрения поддержки Linux, нам нужно в первую очередь расширить пункт N5 и N6. Пункт N5 пересекается с предыдущем разделом «Более полная поддержка GCC и Clang». Сделать тесты для проверки системных заголовочных файлов несложно, но трудоемко расширять парсер. Впрочем, про это мы уже говорили, и намного интересней пункт N6.
На самом деле, это самая большая и сложная из используемых у нас система тестирования. Вот, как выглядит эта программа в процессе работы:
Описывать этот инструмент в статье смысла нет, так как он предназначен исключительно для внутреннего использования. Скажу только, что он позволяет очень удобно отслеживать разработчикам результаты их правок в ядре анализатора и добавления новых диагностик.
Так вот, теперь нам предстоит создать аналог такой системы для Linux. Поскольку это очень важная часть процесса разработки анализатора, мы должны подойти к этой задаче со всей серьезностью. Так же нам нужно будет провести большую работу по подбору открытых проектов, на которых и будет осуществляться проверка работоспособности анализатора. С одной стороны, эти проекты не должны быть слишком большие, чтобы не сделать время проверки слишком долгим. С другой, они должны быть «насыщенными»: в разных проектах должны использоваться различные подходы к программированию. То есть, желательно, чтобы где-то активно применялись операторы goto, где-то активно использовались шаблоны, где-то активно работали с Unicode и так далее. Это делает тестирование анализатора более всесторонним. Собрать такую коллекцию исходников весьма непростая задача, требующая время на изучение большого количества открытых проектов.
3. Мониторинг компиляторов
В состав PVS-Studio для Windows идёт GUI утилита Standalone.exe. С её помощью можно удобно работать с отчётами (*.plog-файлами), если не установлена среда разработки Visual Studio:
Но это не главное. Важнее то, что с помощью этой утилиты можно проверить проект, собираемый любой экзотичной или самописной сборочной системой. Впрочем, это не предназначается именно для экзотических ситуаций. Даже если у вас классический makefile, проще выполнить анализ с помощью Standalone, нежели разбираться с документацией PVS-Studio, чтобы прописать в maklefile вызов анализатора.
Standalone позволяет отслеживать запуски компиляторов Visual C++, GCC (MinGW), Clang и собирать всю необходимую для проверки информацию. Выглядит это следующим образом: вы говорите программе «начать слежку», после чего выполняете обыкновенную сборку проекта. Далее вы говорите программе «готово». Начинается анализ всех тех файлов, компиляция которых только что выполнялась.
Кстати, всё это не обязательно делать вручную. Вы можете использовать для проверки проекта на сервере консольную утилиту CLMonitor.exe. Она также собирает информацию о запущенных компиляторов и выполняет проверку проекта.
Реализуя Linux версию, мы сразу решили, что обязательно надо поддержать отслеживание запусков компилятора. Это поможет программистам быстрее и проще знакомиться с анализатором PVS-Studio. Дело в том, что, используя эту утилиту, проект сможет проверить любой член команды, не отвлекая людей, занимающихся поддержкой makefile-ов и вообще системы сборки. В больших проектах далеко не каждый знает, как собственно собирается их приложение. Тем более, не каждый найдет время и желание разбираться, как и куда прописать вызов PVS-Studio. Всё это ещё может быть усложнено наличием автогенерируемого makefile. Понятно, что во всём можно разобраться, но это является существенным барьером на пути первой проверки проекта и удовлетворения исследовательского любопытства.
Вот вы и познакомились с ещё одной подзадачей создания Linux-версии. Мы работаем над разработкой системы мониторинга запусков компиляторов и сборкой всей необходимой информации для проверки.
4. Доработка документации
При написании документации мы всегда сталкиваемся с противоположными желаниями. С одной стороны, мы всегда старались, чтобы продукт оставался простым и понятным, и для работы с ним не нужно было знакомиться с большим руководством. С другой стороны, статический анализ — это достаточно сложный инструмент, и в руководстве должны быть отражены все тонкости работы с ним. Особенно это касается описания диагностических сообщений: их много, и надо чтобы каждое из них было подробно описано и сопровождалось примерами кода.
В результате нам предстоит большая работа по корректировке и пополнению документации разделами, посвященных работе в Linux. Плюс, нам надо придумать, как реализовать возможность пользователям быстро получать информацию по той или иной диагностике. В Visual Studio с этим нет проблем — достаточно нажать в списке предупреждений на код ошибки и откроется соответствующая страница.
Как и что предложить в среде Linux — надо думать. Конечно, всегда есть PDF файл (на 350 страниц) или online документация на сайте, но это нельзя назвать удобным способом доступа к описанию диагностик.
5. Доработка сайта
Сайт, естественно, тоже потребует доработки. Это не программистская задача, но заниматься ей надо, поэтому я решил упомянуть сайт в обучающих целях. Многие программисты думают только о коде и забывают, что в выпуске продукта участвует много других коллег, решающих большое количество скрытых от них задач.
6. Прочее: тестирование, дистрибутив, организация поддержки
Естественно, не надо забывать о тестировании. Хотя многоуровневые тесты выявят большинство проблем, наверняка проявят себя какие-то совершенно неожиданные ошибки или недоработки. Сейчас даже невозможно предположить, что это будет, но мы не питаем иллюзий об идеальности мира. Под Windows мы столкнулись с разнообразнейшими ситуациями, когда вроде и не мы виноваты, но что-то работает неправильно. О некоторых таких неприятных неожиданностях я рассказывал в интервью около 2 лет назад (ищите в статье фразу «К сожалению, вся красота и надежность внутреннего кода иногда разваливается из-за воздействий враждебной окружающей среды»). Уверен, в Linux нас поджидают аналогичные сюрпризы.
Результаты нашей работы надо обернуть в дистрибутив, который можно легко скачать и использовать. Сказать это намного проще, чем сделать. Думаю, понадобится не одна итерация, чтобы сделать это удобным и учесть различные тонкости.
И последнее: мы должны организовать поддержку нового направления. Наши пользователи ценят нас за качественную и оперативную поддержку. С выходом Linux версии увеличится количество запросов, особенно вначале, когда далеко не всё будет работать, и мы должны быть к этому готовы.
7. Планы на будущее
Выше я описал далеко не всё, на что нам нужно будет потратить время, чтобы адаптировать PVS-Studio к Linux. Есть масса более мелких задач, о которых сразу не вспомнишь, да и писать про них неинтересно. Например, мне надо написать эту и множество других статей, которые расскажут людям о том, что появился PVS-Studio для Linux.
Есть и большие задачи, которыми мы займемся позже. Например, как я уже говорил, вначале мы сосредоточились на GCC, и только потом планируем позаниматься с Clang. Я пока даже не знаю, будет ли в первой релизной версии PVS-Studio для Linux поддержка Clang или нет.
Вот еще некоторые из больших задач, которые ожидают нас:
- Интеграция с Qt Creator.
- Интеграция с… (время покажет).
- Доработка и усовершенствование диагностик. Например, внутри PVS-Studio имеются таблицы с информацией о типовых функциях, таких как malloc, memset, std: swap. Эта информация позволяет выявлять многие ошибки некорректно использования функций. Стоит расширить эти таблицы многими функциями, описанными в POSIX.
In progress
Мы с нетерпением ожидаем, когда можно будет что-то представить миру. Надеюсь, я вас заинтересовал, и многим Linux-разработчикам хочется попробовать проверить свои проекты. Если у вас есть желание и время, приглашаю вас заранее вступить в группу beta-тестеров.
Итак, если вы хотите помочь нам проверить работу PVS-Studio для Linux прошу написать нам. Чтобы письма можно было проще обрабатывать, просим указать в теме письма строчку «PVS-Studio for Linux, Beta». Письма отправляйте по адресу support@viva64.com. Просим писать письма с корпоративных ящиков и кратко представиться. Мы будем благодарны всем, кто откликнется, но в первую очередь будем уделять внимание тем людям, которые потенциально со временем могут стать нашими клиентами.
Также прошу в письме дать ответы на следующие вопросы:
- Под какой операционной системой планируется запускать анализатор?
- Какую среду разработки вы используете?
- Какой компилятор используется для сборки проекта?
- Какую сборочную систему вы используете?
Когда появится версия, которую можно будет попробовать, мы напишем всем откликнувшимся письма.
Заранее всем спасибо. Мы будем временами упоминать в статьях, как продвигается развитие PVS-Studio для Linux. Желаю всем пореже запускать отладчик!
Комментарии (6)
28 июля 2016 в 17:32
–3↑
↓
Linux не является операционной системой.28 июля 2016 в 17:39
–1↑
↓
И откуда вы такие умные беретесь?28 июля 2016 в 17:42
0↑
↓
Спорное утверждение, можете объяснить?
28 июля 2016 в 17:38
+1↑
↓
Мы будем благодарны всем, кто откликнется, но в первую очередь будем уделять внимание тем людям, которые потенциально со временем могут стать нашими клиентами.
Отправил вам письмо, потенциально могу стать вашим клиентом, но складывается впечатление, что вы не хотите сотрудничать с разработчиками-одиночками, нацелены больше на большие «кошельки», прав ли я? Ну продадите вы несколько копий крупным компаниям за многие тысячи долларов и на этом все? Крупных компаний мало, а нас разработчиков тысячи. Многие хотят писать качественный код.
28 июля 2016 в 17:42
0↑
↓
Да, мы не хотим сотрудничать с разработчиками-одиночками. Мы нацелены на корпоративных клиентов. Индивидуальным разработчиком статический анализ не нужен в том объёме, чтобы на этом можно было зарабатывать деньги. Мы убедились в этом благодаря проекту CppCat. История вопроса: https://habrahabr.ru/company/pvs-studio/blog/256637/.
28 июля 2016 в 17:43 (комментарий был изменён)
0↑
↓
По поводу «Conditionals with Omitted Operands».
Там же написано, когда это бывает полезно:When it becomes useful is when the first operand does, or may (if it is a macro argument), contain a side effect
Иначе приходится писать код вродеSomeType* z = CallSomeFunctionWithSideEffects(); if (!z) z = SomeOtherFunction();
ВместоSomeType* z = CallSomeFunctionWithSideEffects() ? : SomeOtherFunction();
Например, в C# есть похожая штука:
null-coalescing operator