Static_analysis
Static Analysis and Linters
Section titled “Static Analysis and Linters”Static analysis tools examine source code without executing it to find bugs, style issues, and potential problems. They are essential for maintaining code quality.
Introduction
Section titled “Introduction”Static analysis catches issues early:
- Memory errors (buffer overflows, leaks)
- Uninitialized variables
- Null pointer dereferences
- Race conditions
- Style violations
- Deprecated API usage
clang-tidy
Section titled “clang-tidy”Modern, powerful C++ linter built on Clang.
Installation
Section titled “Installation”# Ubuntu/Debiansudo apt-get install clang-tidy
# macOSbrew install clang-tidy
# Or use LLVM releaseswget https://github.com/llvm/llvm-project/releases/download/llvmorg-17.0.1/clang+llvm-17.0.1-x86_64-linux-gnu-ubuntu-22.04.tar.xzBasic Usage
Section titled “Basic Usage”# Analyze a single fileclang-tidy main.cpp -- -std=c++17
# Analyze entire projectclang-tidy src/*.cpp -- -std=c++17 -I./include
# Fix some issues automaticallyclang-tidy main.cpp --fix -- -std=c++17
# Fix and apply changesclang-tidy main.cpp --fix-errors -- -std=c++17Configuration
Section titled “Configuration”Create .clang-tidy in project root:
---Checks: > clang-diagnostic-*, clang-analyzer-*, modernize-*, performance-*, readability-*, -modernize-use-trailing-return-type, -readability-magic-numbers,
CheckOptions: - key: readability-identifier-naming.ClassCase value: CamelCase - key: readability-identifier-naming.functionCase value: lower_case - key: modernize-use-nullptr.NullMacros value: 'NULL'Key Checks
Section titled “Key Checks”modernize Recommendations
Section titled “modernize Recommendations”// modernize-use-nullptrvoid oldStyle() { char* p = NULL; // Bad char* p2 = nullptr; // Good}
// modernize-use-emplacevoid bad() { std::vector<std::string> v; v.push_back("hello"); // Creates temporary}
void good() { std::vector<std::string> v; v.emplace_back("hello"); // Constructs in place}
// modernize-range-based-forvoid old() { std::vector<int> v = {1, 2, 3}; for (auto it = v.begin(); it != v.end(); ++it) { std::cout << *it << std::endl; }}
void modern() { std::vector<int> v = {1, 2, 3}; for (const auto& x : v) { std::cout << x << std::endl; }}Performance Checks
Section titled “Performance Checks”// performance-unnecessary-value-paramvoid bad(const std::vector<int> v) { // Copies! // Use: const std::vector<int>& v}
// performance-move-const-argvoid bad(std::vector<int> v) { // If v is passed by value, use std::move}void good(std::vector<int> v) { process(std::move(v));}CMake Integration
Section titled “CMake Integration”# Enable clang-tidy in CMakeset(CMAKE_CXX_CLANG_TIDY clang-tidy -header-filter='.*' -checks='clang-analyzer-*,performance-*,readability-*')Or run separately:
# Generate compile_commands.jsoncmake -B build -DCMAKE_EXPORT_COMPILE_COMMANDS=ON
# Run clang-tidy on all filesclang-tidy -p build/compile_commands.json src/*.cppcppcheck
Section titled “cppcheck”Lightweight, focused on memory errors and common mistakes.
Installation
Section titled “Installation”# Ubuntu/Debiansudo apt-get install cppcheck
# macOSbrew install cppcheckBasic Usage
Section titled “Basic Usage”# Check all files in projectcppcheck --enable=all src/
# Enable specific checkscppcheck --enable=memory,unusedFunction src/
# Quiet mode (only errors)cppcheck --quiet src/
# XML outputcppcheck --xml --enable=all src/ 2> errors.xmlCheck Categories
Section titled “Check Categories”| Category | Description |
|---|---|
| error | Bugs and memory errors |
| warning | Potential bugs |
| style | Style issues |
| portability | Cross-platform issues |
| unusedFunction | Unused functions |
| missingInclude | Missing headers |
Examples of Detected Issues
Section titled “Examples of Detected Issues”// Memory errorsint arr[10];arr[10] = 5; // Array index out of bounds
int* p = new int[10];delete p; // Should be delete[] p
// Uninitialized variablesint x;std::cout << x; // Uninitialized read
// Null pointerint* p = nullptr;*p = 5; // Null pointer dereference
// Resource leaksvoid leak() { FILE* f = fopen("file.txt", "r"); // Missing fclose(f)}Configuration
Section titled “Configuration”<!-- suppressions.txt -->// Suppress specific warnings*:/src/third_party/*.cppunmatchedSuppressioncppcheck --suppressions-list=suppressions.txt src/GitLab CI Integration
Section titled “GitLab CI Integration”static-analysis: stage: test script: - cppcheck --enable=all --inconclusive --xml --output-file=cppcheck.xml src/ artifacts: reports: static_analysis: cppcheck.xmlInclude What You Use (IWYU)
Section titled “Include What You Use (IWYU)”Ensures proper header includes.
Installation
Section titled “Installation”# Ubuntusudo apt-get install include-what-you-use
# macOSbrew install include-what-you-use# Basic usageinclude-what-you-use main.cpp -- -std=c++17
# With CMakeinclude-what-you-use -Xiwyu --verbose=3 main.cpp -- -std=c++17 -I./includeExample
Section titled “Example”#include <vector> // IWYU: add #include <utility> for std::move#include <string>
void foo() { std::vector<std::string> v; v.emplace_back("test");}Output:
main.cpp:1:1: add include at the top of the file (for std::move) [iwyu]SonarQube
Section titled “SonarQube”Enterprise-grade code quality platform.
Installation (Docker)
Section titled “Installation (Docker)”docker run -d --name sonarqube -p 9000:9000 sonarqube:latestConfiguration
Section titled “Configuration”# sonar-scanner.propertiessonar.projectKey=myprojectsonar.sources=srcsonar.cxx.clangtidy.reportPaths=clang-tidy-report.txtsonar.cxx.cppcheck.reportPaths=cppcheck-report.xmlGitHub Actions Integration
Section titled “GitHub Actions Integration”- name: SonarQube Scan uses: SonarSource/sonarqube-scan-action@master env: SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}PVS-Studio
Section titled “PVS-Studio”Commercial static analyzer for Windows, Linux, macOS.
Installation
Section titled “Installation”# Download from https://pvs-studio.com/order/open-source-license/# Linux:wget https://files.pvs-studio.com/files/pvs-studio-7.24.49414.debsudo dpkg -i pvs-studio-7.24.49414.deb# Analyze compile_commands.jsonpvs-studio-analyzer analyze -o pvs.log -C compile_commands.json
# Convert to other formatspvs-studio-html-report pvs.log -o pvs-report.htmlpvs-studio-junit-simple pvs.log -o pvs-junit.xmlCMake Integration
Section titled “CMake Integration”find_package(PVSStudio)if(PVSStudio_FOUND) add_custom_target(pvs-studio ALL COMMAND pvs-studio-analyzer analyze -o ${CMAKE_BINARY_DIR}/pvs.log -C ${CMAKE_EXPORT_COMPILE_COMMANDS} COMMENT "Running PVS-Studio analyzer..." )endif()Code Coverage with clang
Section titled “Code Coverage with clang”Installing Coverage Tools
Section titled “Installing Coverage Tools”# Ubuntusudo apt-get install llvmBasic Coverage Analysis
Section titled “Basic Coverage Analysis”# Compile with coverageclang++ -fprofile-instr-generate -fcoverage-mapping -o test test.cpp
# Run to generate .profraw./test
# Generate coverage reportllvm-profdata merge -o coverage.profdata default.profrawllvm-cov show ./test -instr-profile=coverage.profdata
# HTML reportllvm-cov report ./test -instr-profile=coverage.profdata \ -show-regions -show-line-counts-or-regionsGitHub Actions
Section titled “GitHub Actions”- name: Test and Coverage run: | cmake -B build -DCMAKE_BUILD_TYPE=Debug -DENABLE_COVERAGE=ON cmake --build build ctest --output-on-failureIntegrating in CI/CD
Section titled “Integrating in CI/CD”GitHub Actions Example
Section titled “GitHub Actions Example”name: Static Analysis
on: [push, pull_request]
jobs: analyze: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3
- name: Install clang-tidy run: sudo apt-get install clang-tidy
- name: Run clang-tidy run: | cmake -B build -DCMAKE_EXPORT_COMPILE_COMMANDS=ON find src -name "*.cpp" -exec clang-tidy -p build/ {} \;
- name: Run cppcheck run: | sudo apt-get install cppcheck cppcheck --enable=all --inconclusive src/GitLab CI Example
Section titled “GitLab CI Example”stages: - analyze
clang-tidy: stage: analyze image: ubuntu:22.04 before_script: - apt-get update && apt-get install -y clang-tidy cmake build-essential - cmake -B build -DCMAKE_EXPORT_COMPILE_COMMANDS=ON script: - find src -name "*.cpp" -exec clang-tidy -p build/ {} \; allow_failure: true # Warnings don't fail CI
cppcheck: stage: analyze image: ubuntu:22.04 before_script: - apt-get update && apt-get install -y cppcheck script: - cppcheck --enable=all --inconclusive --xml src/ 2> cppcheck.xml artifacts: reports: static_analysis: cppcheck.xmlBest Practices
Section titled “Best Practices”- Run in CI: Integrate static analysis in your pipeline
- Fix warnings: Don’t let warnings accumulate
- Configure wisely: Tune checks for your codebase
- Start simple: Enable core checks first, add more gradually
- Use multiple tools: Different tools catch different issues
- Automate fixes: Use —fix for auto-fixable issues
- Baseline: Create exceptions for existing issues, fix new ones
Comparison
Section titled “Comparison”| Tool | Focus | Open Source | Performance |
|---|---|---|---|
| clang-tidy | Modern C++ | Yes | Fast |
| cppcheck | Memory errors | Yes | Medium |
| IWYU | Includes | Yes | Fast |
| SonarQube | Quality | Partial | Slow |
| PVS-Studio | General | Commercial | Medium |
Key Takeaways
Section titled “Key Takeaways”- Static analysis catches bugs early without execution
- clang-tidy provides modern C++ recommendations
- cppcheck focuses on memory errors
- IWYU ensures proper includes
- Integrate tools in CI/CD for consistent quality
- Combine multiple tools for comprehensive coverage