Реактор образовательный: поиск ошибок в коде на раннем этапе
Каждый программист знает об отладчике, системе контроля версий или, например, юнит-тестах. Но далеко не все программисты знакомы с методологией статического анализа кода. А тем временем, эта технология становится неотъемлемой частью цикла разработки программ. Предлагаю небольшой ликбез для всех, кто интересуется современными тенденциями разработки.
Чем раньше ошибка выявлена, тем дешевле её исправление. Именно поэтому, например, появилась методология TDD (разработка через тестирование), в которой тесты пишутся до реализации очередной функции.
Ещё одна методология, позволяющая выявить ошибку на раннем этапе, это обзор кода. Грубо говоря, после написания кода программист показывает его коллеге, и тот его проверяет. Это, конечно, "деревенский подход". Полноценный обзор кода — это целый процесс, который хорошо описан, например, в книге С. Макконнелла "Совершенный код". Кстати, каждый, кто называет себя хорошим программистом, просто обязан почитать эту книгу.
И вот методология обзора кода стала подводить. Вернее, методология работает по-прежнему хорошо, но становится всё более дорогой. Собственно, вспомните, когда последний раз ваши свежие функции честно прочитала группа из четырёх программистов, выдала рекомендации, а потом собралась ещё раз, чтобы посмотреть измененный код? А было ли вообще хоть раз такое?
Причина дороговизны в росте размера программного кода и экспоненциальном росте сложности его анализа человеком. Дело в том, что с ростом проекта сложность и количество ошибок растёт нелинейно.
20-30 лет назад можно было взять и проверять весь код на обзорах, а сейчас это неприемлемо сложно и дорого. Просто, для пояснения, приведу два числа:
Количество строк кода в первом компиляторе C++ (Cfront 1.0): 85 KLOC. Количество строк кода в современном компиляторе Clang (без учёта LLVM): 1700 KLOC.И вот здесь на помощь пришел статический анализ кода. Идея в том, что обзор кода выполняет не человек, а программа. Да, программа проверит код хуже, чем 4 пары внимательных глаз. Только вот нет этих глаз. Код некому и некогда читать. Поэтому использование статических анализаторов - очень хорошая альтернатива.
Да, многие ошибки статические анализаторы не находят. Это сложные экспертные системы, но не искусственный интеллект. Зато они не устают, у них всегда есть время проверить ваш код. Более того, в них закладывается огромное количество знаний об ошибочных паттернах, и они способны выявить ошибку, о существовании которой программист может не знать. Так что иногда статический анализ даже превосходит разработчика.
Приведу пример для С++ программистов. Пусть мы имеем цикл, организованный с помощью итераторов. Если в нём изменить контейнер, то итераторы станут невалидными. Это является ошибкой: возникает неопределённое поведение программы. Про это написано в книгах по программированию. Новый стандарт языка C++ подарил программистам range-based for loop. Это менее знакомая конструкция, и, как результат, велик шанс, что будет написан вот такой код:
Так делать нельзя. Для реализации range-based for loop компилятор использует всё те же итераторы. Только они скрыты от нашего взгляда. И после удаления элементов из контейнера итераторы становятся невалидными.
Статический анализатор кода знает о таком паттерне ошибки и выявляет его. Приведенный выше фрагмент кода был выявлен с помощью анализатора PVS-Studio в коде СУБД ClickHouse, которую разрабатывает компания Яндекс для решения задач Яндекс.Метрики. Подробности можно почитать в статье: https://habrahabr.ru/company/pvs-studio/blog/337182/
Существует множество статических анализаторов кода для различных языков программирования. Google поможет найти и познакомиться с ними. Я предлагаю обратить внимание на популярный на Хабре инструмент — PVS-Studio. Это мощный статический анализатор для поиска ошибок и потенциальных уязвимостей в коде на языке C, C++, C#. Работает в Windows и Linux. Платный, но есть варианты бесплатного лицензирования.
Инструмент хорошо ищет разыменования нулевого указателя, неопределённое поведение, 64-битные ошибки и так далее. Но особенно он хорош при поиске различных опечаток и неудачного copy-paste. Про такие ошибки обычно говорят, что их можно найти за 5 секунд. Поэтому авторы анализатора даже создали ресурс для троллинга таких товарищей.
Критикам предлагается найти ошибки (которые находит PVS-Studio) не за 5, а аж за целых 60 секунд. Попробовать себя можно: https://habrahabr.ru/company/pvs-studio/blog/237219/. Предупреждаю сразу, что тест на телефонах работает плохо и рассчитан на наличие компьютерной мышки.
Статический анализ не конкурирует с другими методами борьбы с ошибками, а дополняет их. Отчёт инструментов статического анализа напоминает предупреждения компилятора, но реализован на более качественном уровне. И именно за эту мощь они берут деньги. Аналогия: есть Paint и Gimp, но Photoshop и CorelDRAW очень востребованы. Специализированные утилиты не только более глубоко анализируют код, но и предоставляют массу вспомогательных механизмов для работы с предупреждениями.
Желающим узнать больше, запрос "статический анализ кода" в Google путь покажет.
Подробнее
$16,000 Процент ошибок % Дефектов, найденных на этом этапе % Дефектов, найденных на этом этапе $ Стоимость исправления дефекта на этом этапе Написание ЦпК-тест Функциональный Системный После релиза кода тест тест
Размер проекта (число строк кода) менее 2К 2К-16К 16К-64К 64К-512К 512К и более Типичная плотность ошибок 0-25 ошибок на 1000 строк кода 0-40 ошибок на 1000 строк кода 0.5 - 50 ошибок на 1000 строк кода 2-70 ошибок на 1000 строк кода 4 - 100 ошибок на 1000 строк кода
using Strings = std::vector<std::string>; int mainEntryClickhousePerformanceTest(int argc, char ** argv) { Strings input_files; for (const String filename : input_files) { FS::path file(filename); if (!FS::exists(file)) throw DB: : Exception(....); if (FS::is_directory(file) ) { __________________________________ input_files.erase( std::remove(input_files.begin(), input_files.end() , filename) , input_files.end() ); getFilesFromDir(file, input_files, recursive); } else { if (file.extension().string() != ".xml") throw DB: : Exception(....); } } }
This error was found in the Qt project by PVS-Studio C/C++ static code analyzer. 5 of 15 questions QQuickJSContext2DPrototype::method_getImageData(....) { qreal x = ctx->callData->args[0].toNumber(); qreal y = ctx->callData->args[1].toNumber(); qreal w = ctx->callData->args[2].toNumber(); qreal h = ctx->callData->args[3].toNumber(); if (!qlsFinite(x) I I !qlsFinite(y) I I !qlsFinite(w) I I !qlsFinite(w)) V4THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "getlmageData(): Invalid arguments"); } f 58 seconds left Ï Don’t know
программирование,it,c++,C#,реактор образовательный,geek,Прикольные гаджеты. Научный, инженерный и айтишный юмор
и на основе этого научится находить уязвимости/закладки в новом коде.
Такой ИИ будет проводить аудит кода.
А ещё чтобы ИИ указывал, где человек применил анти-паттерны, где код запутан,
и места где можно упростить код, для лучшей поддержки новыми сотрудниками.
P.S. А на другие языки не планируете расширяться? Golang, например?
даже в яве статический анализ уже не так полезен, не говоря уже про более новые языки, которые и запроектированы были так, чтоб типичные косяки избегать, и системы типов более человеческие там есть, да и элементы статического анализа в самом компиляторе могут быть, а не прилеплены сбоку
Прошу прощения, на первом графике опечатка. А поправить пост уже не могу.
Синяя полоса - кол-во дефектов, внесённых на этапе, а не найденных.
Говнокодер-виндузятник опять пиарит своё недоподелие, которое ищет ошибки хуже clang'овского анализатора.
https://www.viva64.com/ru/b/0108/
https://www.viva64.com/ru/b/0155/
и самое свежее - https://www.viva64.com/ru/b/0446/
Ещё аргументы? :)
Какие синтетические тесты? Я ненавижу синтетические тесты! Proof: https://www.viva64.com/ru/b/0471/
Во сказанул...