3.4: Static Analysis Integration

Overview

Static analysis tools examine source code without executing it, detecting bugs, security vulnerabilities, code smells, and compliance violations. For safety-critical embedded systems governed by ASPICE, ISO 26262, and IEC 61508, static analysis is not optional—it is a core verification activity required for certification.

This chapter covers tool selection, integration strategies, and workflows that enable continuous quality monitoring and "shift-left" defect prevention.


Key Terms

Term Definition
Static Analysis Automated examination of source code without execution to find defects
MISRA Motor Industry Software Reliability Association coding guidelines
SAST Static Application Security Testing—security-focused static analysis
Quality Gate CI/CD checkpoint that fails builds if quality thresholds are not met
False Positive Analysis finding that is not a real defect
Taint Analysis Tracking untrusted data through code to find injection vulnerabilities

Tool Comparison

Tool Type MISRA Support ISO 26262 Qualified Cost Best For
Coverity Commercial Full MISRA C/C++ Yes (TÜV SÜD) $$$ Automotive, aerospace
Polyspace Commercial Full MISRA Yes $$$ Safety-critical, formal methods
SonarQube Open-source Plugin-based No Free-$$$ Enterprise quality gates
Cppcheck Open-source Good coverage No Free Lightweight IDE integration
Clang-Tidy Open-source Partial No Free LLVM ecosystem
PC-lint Plus Commercial Full MISRA No $$ Legacy codebases
Parasoft C/C++test Commercial Full MISRA Yes $$$ DO-178C, automotive

SonarQube Integration

SonarQube provides a centralized quality platform with dashboards, trend analysis, and quality gates. For embedded C/C++ projects, combine SonarQube with specialized analyzers.

Installation

# Docker deployment
docker run -d --name sonarqube \
  -p 9000:9000 \
  -v sonarqube_data:/opt/sonarqube/data \
  -v sonarqube_logs:/opt/sonarqube/logs \
  sonarqube:lts-community

# Wait for startup, then access http://localhost:9000
# Default credentials: admin/admin

Project Configuration

Create sonar-project.properties in your project root:

# Project identification
sonar.projectKey=door-lock-controller
sonar.projectName=Door Lock Controller ECU
sonar.projectVersion=1.0.0

# Source configuration
sonar.sources=src
sonar.tests=test
sonar.sourceEncoding=UTF-8

# C/C++ configuration (requires SonarQube Developer Edition or cxx-community plugin)
sonar.cxx.file.suffixes=.c,.h,.cpp,.hpp
sonar.cxx.includeDirectories=include,drivers/inc,rte/inc

# External analyzer reports
sonar.cxx.cppcheck.reportPaths=build/cppcheck-report.xml
sonar.cxx.clangsa.reportPaths=build/clang-sa-report.plist
sonar.cxx.coverage.reportPaths=build/coverage.xml
sonar.cxx.xunit.reportPaths=build/test-results.xml

# Quality gate
sonar.qualitygate.wait=true

CI/CD Pipeline Integration

# GitLab CI example
stages:
  - analyze
  - quality-gate

static-analysis:
  stage: analyze
  image: gcc:12
  script:
    # Run Cppcheck
    - cppcheck --enable=all --xml --xml-version=2 src/ 2> build/cppcheck-report.xml
    
    # Run Clang Static Analyzer
    - scan-build -o build/clang-sa --plist-html make clean all
    
    # Convert plist to SonarQube format
    - python3 scripts/plist_to_sonar.py build/clang-sa/*.plist > build/clang-sa-report.plist
  artifacts:
    paths:
      - build/*.xml
      - build/*.plist

sonarqube-scan:
  stage: quality-gate
  image: sonarsource/sonar-scanner-cli:latest
  dependencies:
    - static-analysis
  script:
    - sonar-scanner
      -Dsonar.host.url=$SONAR_HOST_URL
      -Dsonar.login=$SONAR_TOKEN
  allow_failure: false

Coverity Integration

Coverity is the industry standard for safety-critical static analysis, with TÜV SÜD qualification for ISO 26262 ASIL D and IEC 61508 SIL 4.

Build Capture

Coverity intercepts your build to understand code structure:

# Capture the build
cov-build --dir cov-int make clean all

# Analyze captured data
cov-analyze --dir cov-int \
  --all \
  --enable-constraint-fpp \
  --enable-fnptr \
  --enable-virtual \
  --security \
  --concurrency \
  --aggressiveness-level high

# Generate reports
cov-format-errors --dir cov-int --html-output cov-html
cov-format-errors --dir cov-int --json-output-v7 cov-results.json

MISRA Compliance Configuration

# coverity-config.yaml
analysis:
  checkers:
    misra:
      enabled: true
      standard: MISRA-C-2012
      rules:
        mandatory: error
        required: error
        advisory: warning
    
    security:
      enabled: true
      checkers:
        - BUFFER_SIZE
        - OVERRUN
        - NEGATIVE_RETURNS
        - TAINTED_SCALAR
        - SQL_INJECTION
        - COMMAND_INJECTION
    
    concurrency:
      enabled: true
      checkers:
        - RACE_CONDITION
        - DEADLOCK
        - LOCK_EVASION

  exclusions:
    paths:
      - third_party/**
      - generated/**
    
  deviation_management:
    require_comment: true
    require_approval: true

Coverity Connect CI Integration

# GitHub Actions example
coverity-scan:
  runs-on: self-hosted
  steps:
    - uses: actions/checkout@v4
    
    - name: Coverity Build Capture
      run: |
        cov-build --dir $COV_DIR make clean all
    
    - name: Coverity Analysis
      run: |
        cov-analyze --dir $COV_DIR \
          --misra-config misra-2012.config \
          --security \
          --all
    
    - name: Commit to Coverity Connect
      run: |
        cov-commit-defects --dir $COV_DIR \
          --host $COV_HOST \
          --https-port 8443 \
          --auth-key-file $COV_AUTH_KEY \
          --stream door-lock-controller \
          --version $GITHUB_SHA
    
    - name: Check for New Defects
      run: |
        # Fail if new high/medium defects introduced
        cov-manage-im --host $COV_HOST \
          --auth-key-file $COV_AUTH_KEY \
          --mode defects \
          --show \
          --stream door-lock-controller \
          --status New \
          --impact High,Medium \
          --exit-status-on-defect 1

Cppcheck for Lightweight Analysis

Cppcheck is ideal for fast feedback during development—run it in your IDE and as a pre-commit hook.

IDE Integration (VS Code)

// .vscode/settings.json
{
  "cppcheck.enable": true,
  "cppcheck.cppcheckPath": "/usr/bin/cppcheck",
  "cppcheck.includePaths": [
    "${workspaceFolder}/include",
    "${workspaceFolder}/drivers/inc"
  ],
  "cppcheck.defines": [
    "STM32F4xx",
    "USE_HAL_DRIVER"
  ],
  "cppcheck.suppressions": [
    "missingIncludeSystem",
    "unmatchedSuppression"
  ],
  "cppcheck.standard": ["c11", "c++17"],
  "cppcheck.enabledChecks": ["all"],
  "cppcheck.misraAddon": true
}

Pre-Commit Hook

#!/bin/bash
# .git/hooks/pre-commit

echo "Running static analysis..."

# Get list of staged C/C++ files
STAGED_FILES=$(git diff --cached --name-only --diff-filter=ACM | grep -E '\.(c|cpp|h|hpp)$')

if [ -n "$STAGED_FILES" ]; then
    # Run cppcheck on staged files
    cppcheck --enable=all \
             --error-exitcode=1 \
             --inline-suppr \
             --suppress=missingIncludeSystem \
             $STAGED_FILES
    
    if [ $? -ne 0 ]; then
        echo "Static analysis found issues. Please fix before committing."
        exit 1
    fi
fi

echo "Static analysis passed."
exit 0

MISRA Checking with Cppcheck

# Enable MISRA addon
cppcheck --addon=misra.py \
         --addon-python=/usr/bin/python3 \
         --misra-severity=warning \
         --suppress=misra-config \
         --xml --xml-version=2 \
         src/ 2> misra-report.xml

Clang Static Analyzer

Part of the LLVM toolchain, Clang Static Analyzer provides deep path-sensitive analysis.

Scan-Build Wrapper

# Analyze during build
scan-build -v -V \
  -enable-checker alpha.security.ArrayBoundV2 \
  -enable-checker alpha.core.PointerArithm \
  -enable-checker alpha.deadcode.UnreachableCode \
  -enable-checker security.insecureAPI.strcpy \
  -o scan-results \
  make clean all

# View HTML report
open scan-results/*/index.html

Clang-Tidy Integration

# .clang-tidy
---
Checks: >
  *,
  -fuchsia-*,
  -google-runtime-references,
  -llvm-header-guard,
  -modernize-use-trailing-return-type,
  cert-*,
  bugprone-*,
  performance-*,
  readability-*,
  misc-*,
  cppcoreguidelines-*

WarningsAsErrors: >
  bugprone-*,
  cert-*

HeaderFilterRegex: '.*'

CheckOptions:
  - key: readability-identifier-naming.VariableCase
    value: lower_case
  - key: readability-identifier-naming.FunctionCase
    value: CamelCase
  - key: readability-identifier-naming.MacroDefinitionCase
    value: UPPER_CASE
  - key: cppcoreguidelines-avoid-magic-numbers.IgnoredIntegerValues
    value: '0;1;2;4;8;16;32;64;128;256'

AI-Enhanced Static Analysis

Modern AI tools can augment traditional static analysis by understanding context and reducing false positives.

AI Triage Workflow

#!/usr/bin/env python3
"""
AI-Enhanced Static Analysis Triage

Uses LLM to analyze static analysis findings, 
classify severity, and suggest fixes.
"""

import json
import subprocess
from anthropic import Anthropic

def load_findings(report_path: str) -> list:
    """Load static analysis findings from JSON report."""
    with open(report_path) as f:
        data = json.load(f)
    return data.get('issues', [])

def get_code_context(file_path: str, line: int, context_lines: int = 5) -> str:
    """Extract code context around the finding."""
    with open(file_path) as f:
        lines = f.readlines()
    
    start = max(0, line - context_lines - 1)
    end = min(len(lines), line + context_lines)
    
    context = []
    for i, l in enumerate(lines[start:end], start=start+1):
        marker = ">>>" if i == line else "   "
        context.append(f"{marker} {i:4d}: {l.rstrip()}")
    
    return "\n".join(context)

def analyze_finding(finding: dict, code_context: str) -> dict:
    """Use AI to analyze a static analysis finding."""
    client = Anthropic()
    
    prompt = f"""Analyze this static analysis finding for an embedded C/C++ project:

**Checker**: {finding['checker']}
**Severity**: {finding['severity']}
**Message**: {finding['message']}
**File**: {finding['file']}:{finding['line']}

**Code Context**:
```c
{code_context}

Provide:

  1. Is this a TRUE POSITIVE or likely FALSE POSITIVE? (with confidence %)
  2. If true positive, what is the actual risk? (Critical/High/Medium/Low)
  3. Suggested fix (code snippet if applicable)
  4. MISRA/CERT rule violated (if any)

Be concise and technical."""

response = client.messages.create(
    model="claude-sonnet-4-6",
    max_tokens=1024,
    messages=[{"role": "user", "content": prompt}]
)

return {
    "original": finding,
    "ai_analysis": response.content[0].text
}

def main(): findings = load_findings("build/static-analysis.json")

print(f"Analyzing {len(findings)} findings with AI...")

results = []
for finding in findings:
    if finding['severity'] in ['error', 'warning']:
        context = get_code_context(finding['file'], finding['line'])
        analysis = analyze_finding(finding, context)
        results.append(analysis)
        
        # Print summary
        print(f"\n[{finding['severity'].upper()}] {finding['file']}:{finding['line']}")
        print(f"  Checker: {finding['checker']}")
        print(f"  AI Analysis: {analysis['ai_analysis'][:200]}...")

# Save enhanced report
with open("build/ai-enhanced-analysis.json", "w") as f:
    json.dump(results, f, indent=2)

if name == "main": main()


---

## Quality Gates

Quality gates prevent defective code from progressing through the pipeline.

### SonarQube Quality Gate Configuration

```json
{
  "name": "Embedded Safety Quality Gate",
  "conditions": [
    {
      "metric": "new_reliability_rating",
      "op": "GT",
      "error": "1",
      "description": "No new bugs allowed"
    },
    {
      "metric": "new_security_rating",
      "op": "GT", 
      "error": "1",
      "description": "No new vulnerabilities allowed"
    },
    {
      "metric": "new_coverage",
      "op": "LT",
      "error": "80",
      "description": "New code coverage >= 80%"
    },
    {
      "metric": "new_duplicated_lines_density",
      "op": "GT",
      "error": "3",
      "description": "Duplication < 3%"
    },
    {
      "metric": "new_code_smells",
      "op": "GT",
      "error": "10",
      "description": "Max 10 new code smells"
    }
  ]
}

Custom Gate Script

#!/bin/bash
# quality-gate.sh - Custom quality gate for CI/CD

set -e

CRITICAL_MAX=0
HIGH_MAX=5
MISRA_MANDATORY_MAX=0

echo "=== Quality Gate Check ==="

# Parse Coverity results
CRITICAL=$(jq '[.issues[] | select(.impact == "Critical")] | length' cov-results.json)
HIGH=$(jq '[.issues[] | select(.impact == "High")] | length' cov-results.json)

# Parse MISRA results
MISRA_MANDATORY=$(grep -c 'Rule.*mandatory' misra-report.txt || echo 0)

echo "Critical issues: $CRITICAL (max: $CRITICAL_MAX)"
echo "High issues: $HIGH (max: $HIGH_MAX)"
echo "MISRA mandatory violations: $MISRA_MANDATORY (max: $MISRA_MANDATORY_MAX)"

# Check thresholds
if [ "$CRITICAL" -gt "$CRITICAL_MAX" ]; then
    echo "FAILED: Too many critical issues"
    exit 1
fi

if [ "$HIGH" -gt "$HIGH_MAX" ]; then
    echo "FAILED: Too many high-severity issues"
    exit 1
fi

if [ "$MISRA_MANDATORY" -gt "$MISRA_MANDATORY_MAX" ]; then
    echo "FAILED: MISRA mandatory rule violations"
    exit 1
fi

echo "=== Quality Gate PASSED ==="
exit 0

Deviation Management

Safety standards require documented justification for any static analysis finding that is suppressed.

Inline Suppression with Justification

/* 
 * DEVIATION: MISRA C:2012 Rule 11.3 (Required)
 * Justification: Hardware register access requires cast from integer to pointer.
 * This is the standard pattern for memory-mapped peripheral access on ARM Cortex-M.
 * Risk: None - address is a known valid hardware register.
 * Approved by: John Smith, 2025-01-15
 * Ticket: SAFETY-1234
 */
/* cppcheck-suppress misra-c2012-11.3 */
volatile uint32_t *GPIO_PORT = (volatile uint32_t *)0x40020000;

Centralized Deviation Database

# deviations.yaml
deviations:
  - id: DEV-001
    rule: MISRA-C-2012-11.3
    scope: drivers/gpio.c
    justification: |
      Hardware register access requires integer-to-pointer cast.
      Standard ARM Cortex-M memory-mapped I/O pattern.
    risk_analysis: |
      No runtime risk. Address is compile-time constant pointing
      to documented hardware register per STM32F4 reference manual.
    mitigations:
      - All register addresses defined in central header
      - Code review required for any new register definitions
    approved_by: John Smith
    approved_date: 2025-01-15
    ticket: SAFETY-1234
    status: approved

  - id: DEV-002
    rule: CERT-EXP36-C
    scope: src/can_driver.c:245
    justification: |
      Pointer to volatile required for DMA buffer alignment.
    # ... additional fields

Metrics and Reporting

Track static analysis metrics over time to identify trends and measure improvement.

Key Metrics

Metric Target Why It Matters
Critical defects 0 Safety-critical issues
High defects < 5 per KLOC Serious bugs
MISRA mandatory violations 0 Compliance requirement
False positive rate < 20% Tool credibility
Mean time to fix < 2 days Team responsiveness
Technical debt ratio < 5% Long-term maintainability

Dashboard Query (SonarQube API)

import requests
import pandas as pd

def get_sonar_metrics(project_key: str, host: str, token: str) -> pd.DataFrame:
    """Fetch static analysis metrics from SonarQube."""
    metrics = [
        'bugs', 'vulnerabilities', 'code_smells',
        'coverage', 'duplicated_lines_density',
        'reliability_rating', 'security_rating'
    ]
    
    response = requests.get(
        f"{host}/api/measures/component",
        params={
            'component': project_key,
            'metricKeys': ','.join(metrics)
        },
        auth=(token, '')
    )
    
    data = response.json()
    measures = {m['metric']: m['value'] for m in data['component']['measures']}
    return pd.DataFrame([measures])

Best Practices Summary

  1. Layer Your Tools: Run fast tools (cppcheck) in IDE, comprehensive tools (Coverity) in CI
  2. Fail Fast: Configure quality gates to block PRs with critical issues
  3. Reduce Noise: Tune configurations to minimize false positives—noisy tools get ignored
  4. Document Deviations: Every suppression needs justification, approval, and ticket reference
  5. Track Trends: Monitor defect density over time, not just absolute counts
  6. Integrate AI: Use AI to triage findings and prioritize fixes
  7. Automate Everything: Manual static analysis never happens consistently

Summary

Static analysis is a cornerstone of safety-critical embedded development. Key integration points:

Layer Tool Purpose
IDE Cppcheck, Clang-Tidy Immediate feedback during coding
Pre-commit Cppcheck Prevent obvious issues from entering repo
CI Coverity, SonarQube Comprehensive analysis + quality gates
Release Coverity + MISRA Certification evidence

Effective static analysis requires:

  • Tool qualification for ISO 26262/IEC 61508 (Coverity, Polyspace)
  • MISRA compliance checking for C/C++ embedded code
  • Quality gates that block defective code
  • Deviation management with audit trail
  • Trend analysis to measure improvement