Как 10 лет назад начинался проект PVS-Studio

в 12:57, , рубрики: 10 лет, C, c++, devops, pvs-studio, viva64, анализ кода, Блог компании PVS-Studio, информационная безопасность, история создания, история старта, история стартапов, Программирование, разработка под windows, разработка приложений, разработка программного обеспечения, статический анализ кода, статический анализатор кода

Единорог

Десять лет назад мы создали простенькую утилиту под названием Viva64, предназначенную для выявления некоторых проблем в 64-битном коде. Так было заложено начало статического анализатора кода PVS-Studio. Хотя с того момента прошло 10 лет, что-то более-менее у нас, как у компании, стало получаться только несколько лет назад. Эта статья — не история успеха, так как мы считаем, что всё интересное только начинается. Однако, 10 лет — это повод подвести промежуточные итоги и рассказать нашим читателям как все начиналось, какие нас ждали ошибки, и что на данный момент у нас получилось. Местами я, возможно, буду не совсем хронологически точен при описании событий. Моя память не идеальна, а 10 лет — это длительный промежуток времени. Желаю всем приятного чтения.

Предыстория

Я (Андрей Карпов) и Евгений Рыжков работали в маленькой тульской компании, занимающейся созданием пакетов численного моделирования и визуализации данных. Работа была интересная и удавалось прикоснуться к передовым по тем временам технологиям. Например, работая с задачами по визуализации данных, мы экспериментировали с 3D очками, работающими по принципу поочередного закрытия глаз. Картинки выводились на ЭЛТ монитор, который показывал изображение то для левого, то для правого глаза. Думаю, мало кто видел такую древность: очки, подключенные к компьютеру по проводу, и ЭЛТ монитор, работающий в чересстрочном режиме (100 кадров в секунду), чтобы на каждый глаз приходилось хотя бы по 50 кадров. Выглядело, на самом деле, всё это ужасно, и моментально начинали болеть глаза, так что ничего удивительного, что широко эта технология не прижилась.

Ещё, например, мы занимались самостоятельным изготовлением бюджетного кластера на основании обыкновенных материнских плат для компьютера. Использовались платы с двумя физическими AMD процессорами. Это сейчас никого не удивишь процессором с 8 ядрами. Тогда же в тульском магазине материнская плата с двумя ядрами — это было чудо чудное, диво дивное. Мы объединили 4 такие платы и получили 8-ядерный мини-кластер, на котором вели различные расчёты. Я непосредственно участвовал в пайке этого устройства:

Рисунок 1. Собранный из подручных материалов мини-кластер. Характеристики: 8 процессоров, 16 гигабайт памяти.

Рисунок 1. Собранный из подручных материалов мини-кластер. Характеристики: 8 процессоров, 16 гигабайт памяти.

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

А ещё мы столкнулись с первыми 64-битными компьютерами, доступными для обыкновенных пользователей. Это были машины с процессорами Opteron и огромным, как мне тогда казалось, объемом памяти в 4 гигабайта. Вот с этих-то машин всё и началось.

В 2005 году вышла Visual Studio 2005, в которой стало возможным разрабатывать 64-битные программы для 64-битной архитектуры (в те времена она называлась AMD64). Помню ещё я ездил в Москву на конференцию компании Microsoft, где демонстрировали как теперь легко и просто можно перекомпилировать код под 64-битный процессор. В общем, 64-битность — это был новый важный тренд в развитии компьютеров.

Конечно, и до этого были 64-битные микропроцессоры. Например, можно вспомнить тот же Itanium. Но именно появление AMD64 оказало существенное воздействие на IT-индустрию: появились 64-битные процессоры, доступные рядовому пользователю, а прикладные Windows-программисты получили возможность писать для этих процессоров программы в привычной среде разработки Visual C++.

В задачах визуализации и численного моделирования большой объём памяти крайне важен. Поэтому, сразу с выходом Visual Studio 2005, мы начали работы по созданию 64-битных версий приложений.

Неудивительно, что мы оказались одними из первопроходцев, адаптирующих свой прикладной код к 64-битным процессорам и, в результате, наступившими на множество новых граблей. Например, выяснилось, что используемые для дистрибуции программ аппаратные ключи защиты ещё не совсем готовы к 64-битности. Не помню, что именно было не так, но пришлось повозиться с новым вариантом защиты кода. Ещё были какие-то нюансы с программой для создания дистрибутивов. Но всё это — мелочи. Самое интересное ждало нас дальше.

Компания Microsoft не обманула, нам действительно достаточно быстро удалось перекомпилировать свои приложения в режиме x64. На это ушло около 3-х недель. И как нам тогда казалось, мы получили 64-битный дистрибутив наших приложений.

Ха! Вот только программы работали неправильно. Причем в их неправильной работе была какая-то подлость. Программы успешно проходили все внутренние тесты, корректно работали на тестовых данных. Но когда мы хотели воспользоваться всей мощью 64-битного приложения, начинались странные непонятные ошибки. Программа начинала глючить, когда выделяла более 10 гигабайт памяти для обработки больших наборов входных данных.

Рисунок 2. У меня не сохранилось картинок, демонстрирующих ошибки визуализации в 64-битном приложении. Я не мог предположить, что через много лет они мне понадобятся. Но эта картинка очень похожа на результат ошибок, которые я наблюдал. Неожиданно могла отрисоваться только часть объекта.

Рисунок 2. У меня не сохранилось картинок, демонстрирующих ошибки визуализации в 64-битном приложении. Я не мог предположить, что через много лет они мне понадобятся. Но эта картинка очень похожа на результат ошибок, которые я наблюдал. Неожиданно могла отрисоваться только часть объекта.

Сейчас-то я знаю все те причины, которые приводили к такому странному поведению программ. Где-то указатель превращали в int, а потом обратно в указатель. Если указатель ссылался на объект в младших 4 гигабайтах памяти, то всё было хорошо. А вот если объект создавался за границей в 4 гигабайта, то проблемы были неизбежны.

Были ошибки и в вычислениях вида:

unsigned int X, Y, Z;
Uint64 Q = X * Y * Z; 

Хотя результат является 64-битной переменной, это не помогает. Переполнение возникает при перемножении 32-битных переменных.

Естественно, есть и множество других способов отстрелить себе ногу. Подробнее со всеми этими бедами можно познакомиться вот здесь: "Коллекция примеров 64-битных ошибок в реальных программах".

Тогда же, в 2005 году, происходящее с нашими программами выглядело непонятной магией. И самое главное, в тот момент мы не понимали, как нам найти и устранить дефекты. Все наши способы неожиданно нам отказали.

Повторю, что юнит-тесты работают корректно и ничего не выявляют. На маленьких тестовых данных тоже всё хорошо. Отлаживаться на больших объемах данных практически невозможно. Во-первых, это очень медленно. Если релиз программы должен работать полчаса, чтобы начали проявлять себя ошибки, то отладочный вариант программы работает долгие часы. Во-вторых, непонятно, а что, собственно, в отладчике смотреть. Не изучать же миллиарды итераций цикла, чтобы найти, когда что-то начинает идти не так. Программисты всегда при отладке стараются использовать минимальный набор данных для воспроизведения ошибки. А здесь на маленьких наборах всё хорошо.

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

Мы поняли, что зашли тупик: знаем, что в программе есть ошибки, но не знаем, как их искать.

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

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

Потом мы познакомились с некоторыми инструментами статического анализа кода и даже купили Gimpel PC-Lint. Но этот анализатор почти ничем нам не помог. Он не был ориентирован на поиск 64-битных ошибок.

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

Как же мы вышли из положения? Мы решили прочитать код. Конечно, не весь. Мы настроили PC-Lint так, чтобы он выдавал предупреждения на все явные приведения типов, на неявное расширение int в 64-битные типы и так далее. Конечно, получилось невероятное количество бесполезных сообщений, но это всё равно лучше, чем просто читать весь код от начала до конца.

Мы изучили потенциально опасные места, на которые, после специальной настройки, нам указывал PC-Lint. Полностью прочитали наиболее важные модули и фукнции. И вот, по прошествии несколько месяцев получили, наконец, стабильную версию 64-битных приложений.

Как вы, возможно, догадались, задачей портирования на 64-битную систему занимались два человека: я и Евгений Рыжков.

Выводы, которые мы тогда сделали:

  • с переходом на 64-битные системы люди будут сталкиваться в своём коде с 64-битными ошибками;
  • эти ошибки очень сложно искать;
  • нет никаких инструментов, помогающих находить такие ошибки.

Приблизительно в это же время происходило другое судьбоносное событие. Евгений Рыжков увлекся чтением книг, посвящённых стартапам и новомодному направлению ISV (Independent software vendor). Впрочем, слова «стартап» тогда, кажется, ещё не было. Во всяком случае в том смысле, в котором есть сейчас.

11 лет назад индустрия телефонов ещё не была развита, не существовало App Store и тому подобного. Если бы существовало, Евгений, возможно, занялся бы созданием игр для телефонов и планшетов. Тогда же он был ограничен обыкновенным компьютером. Он попробовал сделать приложение — раскраску для детей, и попробовал продавать. В целом, получилось всё реализовать и даже сделать несколько продаж, но, конечно, о каком-то успехе и доходах с этого начинания говорить не приходилось. Он начал искать новое применение своих сил.

У меня тоже существовала предпринимательская жилка, и мне хотелось попробовать создать что-то своё. Однако, на тот момент все эти мысли были нечёткими и не находили какого-то реального воплощения. И тут Евгений предложил подумать о создании чего-то этакого, что покорит мир и сделает нас богатыми и известными. В общем заразил меня классической мечтой стартапера. И мы начали думать.

Viva64 версии 1.0

Итак, имеются:

  1. два человека, которые хотят организовать какой-то стартап;
  2. эти два человека знакомы с существованием проблемы поиска ошибок в 64-битных программах на языке С++.

Казалось бы, ну и что тут думать? Надо делать и продавать инструмент для поиска 64-битных ошибок. Однако, мы достаточно долго шли к этой идее. Нам казалось, что это сложная, непонятная задача, которую никто не знает как решать, раз ещё нет инструментария.

Вначале мы перебирали какие-то простые и понятные идеи. Сайты делать не хотелось. Хотелось создавать именно законченный программный продукт. Но вот что предложить миру – мы долго не понимали. Хотелось выбрать направление, в котором может быть реальный спрос, а не только абстрактная красивая идея.

Через некоторое время мы всё-таки начали размышлять над инструментом поиска 64-битных ошибок в программах на языке C и C++. Для начала мы прикидывали, что именно это должно быть. Вначале мы думали над каким-то динамическим анализатором, типа BoundsChecker. Однако, это было слишком сложно, плюс было непонятно, как сделать поиск ошибок некоторых разновидностей.

Постепенно нам стало понятно, что это должен быть статический анализатор кода. Т.е. программа, которая указывает программистам на участки кода, которые надо проверить. Следовало создать инструмент типа PC-Lint или Parasoft C++test, но только ориентированный на поиск специфичных типов ошибок.

Важным вопросом было, посильно ли вообще нам сделать такой инструмент, все-таки речь шла о разборе С++ кода. Пришлось изучать и этот вопрос.

Никакого LLVM в те времена не существовало, поэтому мы рассматривали вариант взять за основу компилятор GCC или какую-то из открытых бесплатных библиотек. Понятно, что ещё были платные библиотеки разбора C++ кода, но мы их даже не рассматривали. GCC нам показался слишком сложным и тяжеловесным, плюс было непонятно, можно ли на его основе как-то создать закрытое приложение. Открытое делать не хотелось, так как непонятно, как на нем заработать. В итоге выбор пал на малоизвестную библиотеку OpenC++. К этому моменту библиотека была заброшена, но нас это не остановило, тем более что она показалась весьма простой, и мы очень быстро смогли написать с её помощью простейшую пробную диагностику.

И вот мы определились и решились, что будем делать инструмент поиска 64-битных ошибок в C/C++ коде. Фактически, это будет классический статический анализатор кода, но в то время мы старались не использовать эти слова. Нам казалось, что это только собьет с толку людей, которые будут искать в интернете «инструмент для поиска 64-битных ошибок».

Имея опыт общения с Gimpel PC-Lint, мы сразу решили, что будем делать инструмент как плагин к Visual Studio. В те времена, чтобы использовать PC-Lint из Visual Studio, нужно было сплясать с бубном. Я даже написал потом небольшую заметку на эту тему, которая, кстати, пользовалась популярностью: Установка PC-Lint и его использование в Visual Studio 2005. В общем, мы считали, что подобная интеграция никуда не годится и надо сразу предоставить пользователям удобный интерфейс. Т.е. человек должен установить инструмент и сразу иметь возможность приступить к проверке проекта. Именно этому принципу наша команда следует до сих пор и считает его очень важным.

В то время мы представляли себе Viva64 как простенькую утилиту, которую будем продавать всего за $200, но массово. Мы думали, что на этот инструмент должен резко появиться спрос в связи с глобальным переписыванием программ для 64-битных процессоров. План был такой: делаем простой инструмент, на который скоро будет большой спрос, продаём его года 3-4. Затем, заработав денег на этом гениальном предвидении, займемся каким-то другим проектом. В общем юношеские фантазии о том, какую крутую идею мы придумали и как быстро на ней поднимемся. Даже вот такой график нарисовали о том, как, на наш взгляд, должен выглядеть спрос:

Рисунок 3. В 2006 году Евгений начертил вот такой график предполагаемой востребованности решения для проверки С++ кода на совместимость с платформой AMD64. Предполагалось, что в 2010 спрос пойдёт на убыль и, вдобавок, Microsoft выпустит какое-то стандартное решение, которое вытеснит анализатор Viva64 с рынка. Однако, за 2-3 года мы надеялись снять "сливки" и накопить денег для будущих начинаний.

Рисунок 3. В 2006 году Евгений начертил вот такой график предполагаемой востребованности решения для проверки С++ кода на совместимость с платформой AMD64. Предполагалось, что в 2010 спрос пойдёт на убыль и, вдобавок, Microsoft выпустит какое-то стандартное решение, которое вытеснит анализатор Viva64 с рынка. Однако, за 2-3 года мы надеялись снять «сливки» и накопить денег для будущих начинаний.

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

И вот состоялось знаковое событие: 31 декабря 2006 года мы выложили первый публичный релиз Viva64 версии 1.00 в интернете. Помню Евгений говорил мне, что выложить надо обязательно до нового года, чтобы в истории версий фигурировал 2006 год. Пользователям будет казаться, что инструмент существует уже хотя-бы год, и это будет придавать ему солидности. Сейчас, по прошествии длинного пути в 10 лет, все это выглядит наивным, но тогда всё это казалось очень важным.

Бюджет создания первой версии анализатора и сайта составил 43200 рублей. Естественно, наше время и силы здесь не учтены. Это были дополнительные расходы. Чтобы легче было понять размер суммы, пересчитаем по курсу доллара тех времен и получим $1710. Можно сказать, что мы все сделали практически без трат.

Начиная с 2007 года, мы начали пробовать продавать наш инструмент, постепенно его усовершенствуя. Работы прибавилось ещё больше. Помимо программирования на прежней работе и программирования анализатора, добавилась работа по продвижению Viva64 в среде программистов. Я и Евгений начали учиться писать статьи, общаться на форумах, пробовать какие-то варианты платной рекламы.

Всё это очень быстро истощало наши моральные и физические силы. Вдобавок, на прежней работе все стало не так светло и радужно. Мы поняли, что больше не можем работать в таком режиме и уволились, временно став безработными.

А продажи всё не шли и не шли. Вернее, что-то чуть-чуть мы сумели продать, но столь мало, что про это даже нет смысла говорить. Мы даже не пробовали вывести деньги, скопившиеся на счету реселлера, так как они бы ничем нам не помогли.

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

Мы искали какие-то варианты найти деньги, чтобы продолжить разработку и верили, что надо продержаться чуть-чуть и начнется рост спроса на наш инструмент. Я уже плохо помню наши хаотичные действия того времени. Помню, например, поход к Сергею Лисицыну в компанию AutomatedQA, офис разработки которой расположен в Туле. Мы пытались заинтересовать его нашими наработками. Но то, чем мы занимались, как-то ни у кого не встречало интереса. Хотя, возможно, мы просто стучались не в те двери или не умели рассказать о себе.

Надо было что-то решать, так как проект Viva64 упрямо отказывался становиться успешным и прибыльным. Мы начали искать подработку в виде аутсорса. Мы брались за всё подряд, что попадалось под руку. Мы успели посотрудничать с компаниями Ingate и Intelsys. Затем мы приняли участие в большом проекте одной итальянской компании. Это была программа для зубных техников, занимающихся изготовлением зубных протезов. На компьютере проектировался зубной мост или коронка, затем специальный станок её вытачивал. Фактически, это была сильно специализированная CAD система. Пришлось вспоминать раздел математики, связанный с матрицами поворота и преобразованием изображений. А заодно узнать, что такое NURBS поверхности.

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

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

Опять начались тяжелые трудовые дни. 8 часов надо посвятить работе над CAD системой, а затем ещё, на сколько хватит сил, заниматься усовершенствованием Viva64, сайта, что-то делать по продвижению. Конечно, теперь не надо было тратить время на поездки в офис, так как мы работали дома. Но ещё неизвестно, что тяжелее. Сидеть безвылазно целыми днями за компьютером очень тяжело. Но, видимо, только так что-то и получается сделать, если хочется вырваться из круговорота однотипных будней. Чтобы произошли изменения, надо начать работать ещё больше.

Популярность проекта Viva64 постепенно росла, но крайне медленно. Мы начали понимать, что никакого быстрого старта не получилось. Но всё ещё наивно надеялись, что он возможен, ещё чуть-чуть и 64-битность начнёт массово волновать программистов.

Забегая вперед скажу, что у темы 64-битнойсти так никогда и не было всплеска. Был очень медленный постепенный переход от 32-битных к 64-битным приложениям. Он идёт и сейчас. До сих пор некоторые клиенты выбирают PVS-Studio, исключительно из-за того, что в нём есть диагностики для выявления проблем, связанных с 64-битностью.

Получается, что с 64-битностью мы одновременно и не ошиблись, и ошиблись. Мы не ошиблись в том смысле, что проблема миграции большой кодовой базы на 64-битную платформу действительно существует. За 10 лет мы продали немало лицензий Viva64, а потом и PVS-Studio для поиска 64-битных ошибок. Но мы ошиблись в оценке временных интервалов. Мы думали, что переход будет активно происходить 2-3 года, и ещё пару лет будет спад. И, исходя именно из этих соображений, начинали проект. Мы рассчитывали на спринт, а ввязались в марафон, в котором участвуем вот уже 10 лет.

Однако, это сейчас мы понимаем, что к чему. В то время мы продолжали верить в «64-битную тему» и занимались развитием анализатора.

Старт 2008, точка невозврата

И вот, в 2008 году судьба нас привела к государственной программе Старт. Вернее, готовиться мы к ней начали в 2007 году, а финансирование получили в 2008. В двух словах расскажу, что это такое. Цитата с сайта:

«Цель Программы — содействие инноваторам, стремящимся разработать и освоить производство нового товара, изделия, технологии или услуги с использованием результатов своих научно-технологических исследований, находящихся на начальной стадии развития и имеющих большой потенциал коммерциализации. Следует иметь в виду, что программа „Старт“ в первую очередь ориентирована на инициативных научных работников, желающих на основе своих инновационных идей создать устойчиво работающий бизнес».

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

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

Для участия в программе требуется создать ООО. Далее, выделяются небольшие деньги (тогда это было 750 000 рублей на год). Но даже эти деньги потратить не так легко. Нельзя просто взять и накупить, например, компьютеров и рекламных баннеров на сайтах. А не потратить нельзя, да и глупо. В результате, необходимость что-то делать с деньгами привела к тому, что мы сняли первый офис. У нас появилось два первых сотрудника. Было куплено для офиса что-то из мебели и так далее.

Рисунок 5. ООО "СиПроВер", 2008 год. Первый день в первом собственном офисе.

Рисунок 5. ООО «СиПроВер», 2008 год. Первый день в первом собственном офисе.

Итого, участие в программе Старт заставило нас выйти из дома и начать не играть в проект Viva64, а реально им заниматься. Старт подтолкнул нас к регистрации ООО, найму первых сотрудников, и вообще заставил чувствовать себя настоящими организаторами компании.

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

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

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

Это был «Ад». И когда заканчивался 2008 год, мы решили, что не будем пытаться продлить наше участие в программе «Старт». Слишком много отнимает бюрократия, причем время и силы, которые мы на неё тратим, расходуются впустую. В это время начали потихоньку идти какие-то продажи Viva64, и мы видели, что явно уделяем проекту меньше сил, чем могли бы. Мы решили, что лучше затянем пояса, но зато будем больше заниматься перспективными направлениями, а не печатью талмудов отчётов. Мы не стали подавать заявку на следующий год. Со стороны такое решение, возможно, покажется глупым. Но я уверен, что тогда мы поступили правильно и, возможно, сэкономили себе 1 или 2 года.

Я упомянул, что начались какие-то продажи Viva64. Да, именно так. Причем мы начали постепенно повышать цену, так как клиентами были крупные компании. Именно тогда закралось подозрение, что мы делаем продукт не для программистов, а для компаний. Впрочем, до осознания того, что мы B2B, было ещё далеко.

VivaMP, первая ошибка

За десять лет мы допустили множество ошибок. Про мелкие рассказывать я не буду, так как это, во-первых, не очень интересно, а, во-вторых, я уже почти всё позабыл. В качестве примера такого мелкого ляпа могу вспомнить, что первый год наше ООО работало не по упрощенной системе налогообложения, а по общей. Мы не знали, что надо подать заявление о переводе на упрощенную систему в первые 5 дней — типичная ошибка новичков. Бедой это не было, так как в первый год ООО заработало мало денег, так что и потеряло тоже крайне мало.

Так что давайте поговорим про более эпические ляпы. Первым из них стал проект VivaMP. Мы начали этот проект ещё в 2008 году, но первый релиз состоялся в марте 2009 года.

Итак, мы уже смирились, что 64-бита не дали нам быстрого «взлёта», и начали искать новое направление, где можем опередить других. И как нам казалось — нашли.

В 2008 году стали массово появляться многоядерные процессоры. На повестке дня программистов стоял вопрос: какая технология будет доминировать в сфере разработки параллельных программ на языке C и C++? Варианты были разные: MPI, OpenMP, какие-то уже существующие библиотеки, или которые могли вскоре появиться.

В то время компания Intel продвигала технологию OpenMP. По крайней мере, нам так казалось. И мы решили повторить рисковый эксперимент: создать инструмент статического анализа кода для параллельных программ, построенных на технологии OpenMP. Вообще, статический анализ кода параллельных программ — задача неблагодарная и в общем случае не решаемая. Здесь царствуют динамические анализаторы кода. Хоть какой-то статический анализ параллельных программ возможен, только если код программы специальным образом размечен, чтобы подсказать анализатору, какие блоки будут выполняться параллельно, а какие нет. Здесь технология OpenMP крайне удачна для анализатора. Директивы "#pragma omp ...." и есть та самая, так необходимая разметка для анализатора.

Мы подробно изучили тему программирования с помощью OpenMP и убедились, что есть ошибки, которые можно выявлять статическим анализом кода. Интересующиеся могут познакомиться с нашей статьёй: "32 подводных камня OpenMP при программировании на Си++".

В целом, новая тема была выбрана неверно. Совсем неверно. Если с 64-битностью интерес был и есть, пусть и не такой большой, как хотелось, то в случае OpenMP интереса не было совсем.

Причин для невезения, видимо, было несколько:

  1. Технология OpenMP не стала мейнстримом. Она занимает скромную позицию наравне с другими технологиями параллельного программирования.
  2. Из пункта один следует, что не так много программистов используют OpenMP в своих проектах. Следовательно, спрос в любом случае будет мал. Помимо этого, мы, видимо, не смогли выйти на эту группу разработчиков и донести до них информацию о существовании инструмента VivaMP.
  3. Статический анализ для поиска ошибок в параллельных программах всё равно слаб и сильно проигрывает другим инструментам.

Проект VivaMP не задался. Он был просто никому не нужен. В почте практически не было вопросов об этом анализаторе или сообщений об ошибках в нём. Мир просто проигнорировал его существование

VivaMP в дальнейшем был интегрирован в PVS-Studio, а в 2014 удалён. Стандарт OpenMP продолжал развиваться, в нем появлялись новые возможности и новые ключевые слова. Их надо было поддерживать, а смысла это делать для мертворожденного инструмента не было. Только трата сил и никакой пользы. Мы собрались с духом и удалили эту часть анализатора.

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

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

PVS-Studio с анализатором общего назначения, первые успехи

В 2009 году мы объединили Viva64 и VivaMP в единый продукт в надежде что диагностики VivaMP будут покупать как довесок к 64-битным диагностикам. Результата это никакого не дало, так что подробнее рассказывать про это смысла нет.

Тем не менее, стоит отметить 2009 год, как важную веху в жизни нашей компании. Именно в этом году появился анализатор PVS-Studio, который вначале представлял собой как раз объединение Viva64 и VivaMP.

Кстати, заодно, давайте поговорим о названиях. Анализатор Viva64 появился как желание выразить мысль: «Да здравствует 64-битный мир!». А именно само слово «viva» было навеяно недавним прослушиванием мною песни «Viva Forever». Я предложил использовать именно такое название Евгению, и он согласился. Аналогичным образом был назван и наш сайт www.viva64.com, который мы никогда не видели смысла переименовывать, так как его название постепенно стало популярным.

Название PVS-Studio образовано более сложным образом. Первые три буквы — это сокращение от названия нашей компании OOO «Program Verification Systems». «Studio» было добавлено, чтобы подчеркнуть, что это не просто один инструмент, а коллекция инструментов, собранных вместе. На самом деле, название не очень удачно, так как его очень часто пишут неправильно: кто-то не ставит черточку, кто-то вместо PVS пишет PSV и так далее. Если бы мы выбирали название сейчас, мы использовали бы что-то более простое. Собственно, так мы и поступили, создавая CppCat, но это совсем другая история, о которой я поговорю ниже.

Вернёмся к основной линии повествования. В 2010 году мы решили, что сможем усилить интерес к анализатору PVS-Studio, добавив к нему немного диагностик общего назначения. Причем эти диагностики мы планировали сделать бесплатными, так как не верили, что на них можно что-то заработать. В сфере диагностик общего назначения для C и C++ в то время царствовали такие инструменты, как Coverity, Parasoft C/C++test, Klocwork, Gimpel PC-Lint и так далее. Мы не видели никакого смысла даже пытаться потеснить эти инструменты. Поэтому бесплатные диагностики общего назначения мы планировали сделать исключительно в рекламных целях. Идея была такая: человек проверяет бесплатно свой проект, а заодно узнает о платных диагностиках, связанных с 64-битностью и OpenMP.

В ноябре 2010 мы выпустили первую бета-версию PVS-Studio 4.00, в которой появился новый набор правил статического анализа общего назначения. На тот момент их было 45 штук. Вот статья про это событие: "Трепещи, мир! Мы выпустили PVS-Studio 4.00 с анализатором общего назначения".

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

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

Мы услышали этот сигнал из космоса и быстро пересмотрели свои подходы. Поэтому вышедшая через месяц релизная версия PVS-Studio 4.00 была уже платной. Пришлось даже написать объяснительную статью, почему мы так быстро передумали: "Почему PVS-Studio 4.00 будет платным решением". Статью можете не читать, так как я скажу, что её смысл сводится к «мы хотим денег».

Итак, PVS-Studio стал представлять собой комплект из трех анализаторов (Viva64, VivaMP, диагностики общего назначения), которые мы начали продавать как единое целое. В этой же версии впервые появились корпоративные лицензии (Site License).

Шло время, анализатор PVS-Studio развивался и постепенно начинал приносить больше денег. В PVS-Studio 4.30 появляется инкрементальный анализ — возможность автоматически запускать анализатор для тех файлов, которые только что были изменены и перекомпилированы. Это позволило начать регулярно использовать PVS-Studio на локальных машинах разработчиков.

А еще в PVS-Studio 4.32, которая вышла в июле 2011 года, мы отказались от лицензий для одного пользователя. Это было ещё одно из самых лучших бизнес-решений в истории компании. Мы поняли, что PVS-Studio — это командный инструмент, который приносит пользу всему проекту, независимо от того, сколько именно человек непосредственно с ним работают.

В начале 2012 года вышел PVS-Studio 4.53, в котором уже насчитывалось 100 сообщений анализа общего назначения (V501-V600). Вскоре также появился набор диагностик «Микро-оптимизации» для поиска тех мест падения производительности, которые можно обнаружить статическим анализом.

Так прошли 3 года, когда мы принимали верные и полезные решения по развитию проекта. Это слишком долго, пора было делать глупости.

Embarcadero RAD Studio, вторая ошибка

История будет короткой, так как особенно и рассказывать не о чем. В PVS-Studio 5.00 появилась интеграция в Embarcadero RAD Studio. Нам казалось, что в мире полно пользователей C++Builder. Мы были неправы. Ну или мы просто их не нашли.

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

Естественно, было потеряно время и силы на поддержку Embarcadero RAD Studio и рекламу новых возможностей.

Впрочем, безумия с Embarcadero RAD Studio нам показалось мало, и мы без отдыха, через год, совершили новую серьезную ошибку.

CppCat, третья ошибка

Мы выпустили продукт CppCat 1.00 — основанный на PVS-Studio недорогой статический анализатор. Мы его называли «альтернативой PVS-Studio за $250». Идея была в том, чтобы выпустить статический анализатор высокого уровня, но за очень небольшие деньги. Он был сильно дешевле. Якобы тогда намного больше разработчиков будут покупать и использовать наши решения. Возможно, мы бы даже тогда совсем отказались от PVS-Studio, который представлялся нам большой и тяжелой программой с историей, в противовес легкому и молодому CppCat, в котором простой интерфейс сочетался с мощным анализом кода.

Думаю, по названию главы вы уже догадались, что это была плохая идея. Я решил не описывать здесь подробности этой ошибки, так как они будут фактически пересказом статьи "Мы закрываем проект CppCat". Крайне рекомендую эту статью к прочтению, она небольшая и весьма интересная.

Рисунок 6. Проект CppCat был хорош всем. У него было простое название, в нем были простые настройки, его мог приобрести себе индивидуальный разработчик. Плохо было одно: он не приносил денег.

Рисунок 6. Проект CppCat был хорош всем. У него было простое название, в нем были простые настройки, его мог приобрести себе индивидуальный разработчик. Плохо было одно: он не приносил денег.

Чуть более чем через год мы закрыли проект CppCat, вновь потратив время и силы впустую. Как видите, мы наделали массу серьёзных ошибок, каждая из которых могла нас разорить. Зато теперь мы стали намного аккуратней и подходим к новым экспериментам более вдумчиво, заранее закладывая ресурсы на случай очередного промаха.

Кстати, чуть ранее закрытия CppCat, мы заодно удалили поддержку Embarcadero RAD Studio и диагностик OpenMP. Мы поняли, что пора избавляться от балласта, который не приносит денег, но всё равно требует усилий на поддержку.

Наши дни

Неудачи с CppCat, VivaMP, Embarcadero RAD Studio не подорвали наш энтузиазм, и мы вложились в три новых направления:

  1. Анализ C# кода;
  2. Поддержка Linux;
  3. Бесплатный вариант лицензии PVS-Studio.

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

Можно отсчитывать время полноценного начала существования нашей компании с 2009 года, когда мы перешли на самоокупаемость без поддержки аутсорсинговых проектов. На тот момент нас было 4 человека. По прошествии 7 лет наша команда PVS-Studio состоит из 24 человек. Конечно, это нельзя называть большим успехом, но как получилось, так и получилось. Я не вижу смысла приукрашивать действительность. Несмотря на 10 лет пути, мы считаем, что находимся только в начале и только учимся по-настоящему делать и продавать наш программный продукт.

Надеюсь, я рассказал вам интересную историю. Буду рад если она воодушевит кого-то не бросать свои начинания и продолжать верить в мечту.

Рисунок 7. Не сдавайтесь!

Рисунок 7. Не сдавайтесь!

Ах да, баги Viva64 v1.0

Я был бы не я, если бы не проверил первую версию анализатора Viva64 с помощью современной версии PVS-Studio. Ошибок нашлось совсем мало в силу крошечного размера ядра анализатора того времени. Нашего кода, так там, вообще, всего 3-4 тысячи строк. На тот момент ядро анализатора Viva64 состояло всего из 210 файлов и насчитывало 37 KLOC. Для сравнения, сейчас ядро PVS-Studio для анализа C/C++ кода состоит из 320 файлов и насчитывает уже 208 KLOC. Соответственно, количество кода, написанного нами, увеличилось где-то в 40 раз.

Примечание. Ещё раз уточню, что речь идёт именно о ядре для анализа C и C++ кода. Помимо этого, существует Plugin для Visual Studio, ядро анализатора для C#, утилита Standalone и так далее. Так что общий размер кода за эти годы вырос в сотни раз.

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

rw_table_sanity_check(const rw_table table[])
{
  unsigned n = (sizeof table)/(sizeof table[0]);
        
  if (n < 2) return;

  for (const char* old = (table++)->name; --n; old = (table++)->name)
      if (strcmp(old, table->name) >= 0) {
          cerr << "FAILED: '" << old << "' < '"
                << table->name << "'" << endl;
          assert(! "invalid order in presorted array");
  }
}

Эта ошибка выявляется сразу двумя предупреждениями PVS-Studio:

  • V511 The sizeof() operator returns size of the pointer, and not of the array, in 'sizeof table' expression. lex.cc 822
  • V514 Dividing sizeof a pointer '(sizeof table)' by another value. There is a probability of logical error presence. lex.cc 822

Ошибка относится к подсистеме юнит-тестов. Тест, на самом деле, ничего не проверяет, так как переменной n присваивается значение 0. Ошибка в том, что table — это просто указатель, а не массив.

А вот ошибка, которую сделал лично я:

bool IsLiteralFFFFFFFF(const char *buf, size_t len) {
  if (len < 10)
    return false;
  
  if (buf[0] != '0' && (buf[1] != 'x' || buf[1] != 'X'))
    return false;
  ....
}

Предупреждение PVS-Studio: V547 Expression 'buf[1] != 'x' || buf[1] != 'X'' is always true. Probably the '&&' operator should be used here. vivacasts.cpp 632

Не работает быстрая проверка, что литерал должен начинаться с символов «0x» или «0X». Проверка считает правильными любые строки, которые начинаются с символа '0'.

Немного длинный код, но я решил его всё-таки не сокращать:

Ptree* Append(Ptree* p, Ptree* q)
{
    Ptree *result, *tail;

    if(p == 0)
        if(q->IsLeaf())                          // <=
            return Cons(q, 0);
        else
            return q;

    result = tail = Cons(p->Car(), 0);
    p = p->Cdr();
    while(p != 0){
        Ptree* cell = Cons(p->Car(), 0);
        tail->SetCdr(cell);
        tail = cell;
        p = p->Cdr();
    }

    if(q != 0 && q->IsLeaf())                    // <=
        tail->SetCdr(Cons(q, 0));
    else
        tail->SetCdr(q);

    return result;
}

Предупреждение PVS-Studio: V595 The 'q' pointer was utilized before it was verified against nullptr. Check lines: 360, 374. ptreeutil.cc 360

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

Следующий код вполне оправдан для тех времён, но сейчас так писать уже нельзя:

Class* Environment::LookupClassMetaobject(Ptree* name)
{
    TypeInfo tinfo;
    Bind* bind = 0;

    if (this == 0) {
        TheErrorLog().Report(
            MopMsg(Msg::Fatal, 
                   "Environment::LookupClassMetaobject()", 
                   "0 environment"));
        return 0;
    }
  ....
}

Предупреждение PVS-Studio: V704 'this == 0' expression should be avoided — this expression is always false on newer compilers, because 'this' pointer can never be NULL. environment.cc 115

Таких проверок ещё есть с 10 штук.

На этом всё. Наверное, мои читатели ждали большего, но, действительно, больше ничего заслуживающего внимания нет. Просто 37 KLOС — это очень мало, и мы всегда очень тщательно подходили к написанию кода и тестированию.

Заключение

Из интересных наблюдений я могу сказать, что 10 лет назад я представлял организацию работы фирмы сильно по другому. Мне казалось, что когда всё наладится, я и Евгений будем заниматься творческими вопросами, разрабатывать стратегии развития и вообще сидеть в креслах с умным задумчивым видом. Но выяснилось, что чем дальше, тем больше наша работа напоминает работу пожарных, которые самоотверженно должны сражаться с различными бедами. А чем большее количество площади в офисе мы занимаем, и чем больше сотрудников, тем больше становится этих «пожаров» и тем более они разнообразны по своей природе. Примеры: проблемы с электричеством, протечки потолка, заклинивший замок в двери, ликвидация нарушения в виде недоплаченного налога в размере 1 копейки, и так далее. Это, конечно, не значит, что лично я или Евгений полезем самостоятельно менять кондиционер, пробитый этой зимой сосулькой. Однако, организовать его починку нужно будет именно нам.

Рисунок 8. Свежая зимняя проблема. Вот так выглядят трудности стартапов. Они вовсе не в том, что выбран не тот Framework.

Рисунок 8. Свежая зимняя проблема. Вот так выглядят трудности стартапов. Они вовсе не в том, что выбран не тот Framework.

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

Рисунок 9. Я и Сергей Хренов за изготовлением правильного Press Wall. Хочешь сделать что-то хорошо, сделай это сам.

Рисунок 9. Я и Сергей Хренов за изготовлением правильного Press Wall. Хочешь сделать что-то хорошо, сделай это сам.

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

Спасибо всем за внимание. На этом я заканчиваю и поздравляю всех с наступающим Новым годом.

Как 10 лет назад начинался проект PVS-Studio - 11


Если хотите поделиться этой статьей с англоязычной аудиторией, то прошу использовать ссылку на перевод: Andrey Karpov. PVS-Studio project — 10 years of failures and successes.

Автор: PVS-Studio

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js