Какие инструменты для статического и динамического анализа кода на C++ ты использовал?

Ответ

В своей практике для обеспечения качества кода на C++ я активно использую комбинацию статических и динамических анализаторов.

Статический анализ (SAST):

  • Clang-Tidy / Clang Static Analyzer: Мои основные инструменты, интегрированные в CI/CD. Они отлично находят potential bugs, нарушения code style (например, Google C++ Style Guide), упрощения кода (modernize-* checks).
    # Пример запуска
    clang-tidy -checks='*' myfile.cpp -- -std=c++17
  • Cppcheck: Использую для поиска специфических проблем, которые могут ускользнуть от других анализаторов, например, ошибок с границами массивов или утечек ресурсов.
  • PVS-Studio: Мощный коммерческий анализатор, который глубоко анализирует код и находит сложные ошибки (VLA, copy-paste). Использую его для периодического глубокого аудита критичных модулей.

Динамический анализ (DAST):

  • Valgrind (Memcheck, Helgrind): Незаменим для отладки утечек памяти, ошибок работы с неинициализированной памятью и проблем с многопоточностью (data races) в Linux.
    // Код, который Valgrind Memcheck обнаружит как ошибку
    int* ptr = new int(42);
    delete ptr;
    // Ошибка Use-after-free
    std::cout << *ptr << std::endl;

    Запуск: valgrind --leak-check=full ./my_program

  • AddressSanitizer (ASan), UndefinedBehaviorSanitizer (UBSan): Инструменты от LLVM, которые я предпочитаю за скорость (в сравнении с Valgrind). Они компилируются вместе с кодом и отлавливают ошибки памяти (разыменование nullptr, выход за границы массива) и неопределённое поведение (переполнение знакового целого, сдвиг на отрицательное число).
    # Компиляция с AddressSanitizer
    clang++ -fsanitize=address -g -O1 myfile.cpp
  • Google Test / Catch2 с профилировщиком покрытия (gcov, llvm-cov): Для модульного тестирования и отслеживания coverage. Цель — поддерживать высокий процент покрытия ветвлений (branch coverage) для критического кода.

В рабочем процессе эти инструменты интегрированы в систему сборки (CMake) и пайплайн CI, что позволяет отлавливать проблемы на ранних этапах.

Ответ 18+ 🔞

Слушай, я тебе сейчас как есть расскажу, как я на C++ код проверяю, чтобы потом не охуеть от багов в продакшене. Это, блядь, целая наука, но если по делу — я жму и на статику, и на динамику, как последний маньяк.

Статика, или когда код ещё не запущен, а уже воняет (SAST):

  • Clang-Tidy / Clang Static Analyzer: Это мои рабочие лошадки, ёпта. Они вшиты в CI/CD так, что если какой-то долбоёб напишет кринж — сборка просто не соберётся. Ищут всё: от потенциальных глюков до нарушения стиля (типа, забыл const& там, где надо). Просто золото.
    # Пример запуска
    clang-tidy -checks='*' myfile.cpp -- -std=c++17

    Честно, иногда он такое находит, что я сам от себя охуевал — типа, «какого хуя я это три года назад написал?».

  • Cppcheck: Его я пускаю отдельно, для подстраховки. Он иногда такие заковыристые косяки вылавливает, особенно с памятью или границами массивов, что другим не снилось. Доверия к нему — ебать, ноль, но проверить стоит.
  • PVS-Studio: Ну это, блядь, тяжёлая артиллерия. Дорогой, мощный, коммерческий. Я его включаю раз в квартал на самых ответственных кусках кода, и он всегда находит какую-нибудь дичь — вроде копипасты с ошибкой или скрытого неопределённого поведения. После его отчёта обычно волнение ебать — столько работы пофиксить.

Динамика, или когда код уже бежит и его надо добить (DAST):

  • Valgrind (Memcheck, Helgrind): Старый добрый дедушка. В Линуксе без него — как без рук, если память течёт или в потоках бардак. Правда, тормозит он, ядрёна вошь, так что для быстрых проверок не очень.
    // Код, который Valgrind Memcheck обнаружит как ошибку
    int* ptr = new int(42);
    delete ptr;
    // Ошибка Use-after-free
    std::cout << *ptr << std::endl;

    Запускаешь valgrind --leak-check=full ./my_program и смотришь, как он тебе вываливает овердохуища предупреждений. Праздник души.

  • AddressSanitizer (ASan), UndefinedBehaviorSanitizer (UBSan): А вот это моя настоящая любовь. Инструменты от LLVM, которые встраиваются прямо в бинарь. Быстрые, как чёрт, и ловят всё: обращение в нулль, выход за границу массива, переполнение инта. ASan'у доверия — ебать, 100%, он редко врёт.
    # Компиляция с AddressSanitizer
    clang++ -fsanitize=address -g -O1 myfile.cpp

    Запустил — и если есть проблема, он тебе сразу строку и стектрейс в морду тычет. Красота.

  • Google Test / Catch2 с покрытием (gcov, llvm-cov): Ну и куда же без тестов, ёпта. Пишем тесты, гоняем их, а заодно и смотрим, какой процент кода они реально покрывают. Для критичных модулей цель — чтобы покрытие ветвлений было под 90%, иначе чувствую подозрение, что где-то затаился хуй с горы.

Короче, весь этот зоопарк у меня зашит в CMake и CI-пайплайн. Собирается проект — сразу всё это добро запускается. Если что-то сломал — тебе сразу прилетает оповещение, и ты идёшь фиксить, пока не впендюрили в мастер. Система, блядь, не идеальная, но работает.