Skip to content

Static Analysis (MISRA C:2023 / CERT C / CWE)

Detects MISRA C:2023, SEI CERT C, and CWE violations in C files and provides AI-powered fix suggestions. Standards are opt-in per run (default: MISRA).

Detection is backed by cppcheck's misra addon, which statically detects a subset of the rule set — 130 of the 133 recognised MISRA rules as of the pinned cppcheck 2.20.0. Rules requiring whole-program or full semantic analysis (8.13, 17.4, 17.5) are not detected and need manual review. See the rule coverage matrix for the exact, machine-derived list — we don't claim coverage we can't back up.

How It Works

  1. The extension sends the current file path (or code snippet) to the daemon
  2. The daemon invokes cppcheck via the Python engine, with the requested standards
  3. Each violation is classified by standard (MISRA C:2023 / CERT C / CWE), with its CWE id where applicable
  4. (Optional) An LLM generates fix suggestions with diffs

Usage

From GitHub PR

The sidebar appears automatically on GitHub PR pages. Click MISRA Check to analyze the changed files.

API

curl -X POST http://localhost:9400/api/v1/analyze \
  -H "Content-Type: application/json" \
  -d '{
    "file_path": "/path/to/source.c",
    "rules": ["8.7", "15.5"],
    "suggest": true,
    "llm_mode": "local"
  }'

The daemon forwards the same build-context and adoption flags the CLI exposes, so the extension and CI get identical analysis:

Field Maps to Notes
project --project Path to a compile_commands.json; whole-project mode (Pro, like batch).
includes -I Array of header search paths.
defines -D Array of NAME[=value] macros.
undefines -U Array of macros to undefine.
std / platform --std / --platform e.g. c11, unix64.
rules --rules Allow-list of rule ids to report — MISRA numbers, CERT ids or CWE; empty = all. Full ruleset still runs; only the report is filtered.
baseline --baseline Report and gate on new violations only.
no_inline_suppress --no-inline-suppress Disable provadyne-ignore deviations (on by default).

project and baseline paths are confined to the daemon's allowed analyze directory; a path that escapes it is rejected with 403.

CLI

# default: MISRA C:2023 only
python -m engine.misra.checker /path/to/source.c

# all three C standards
python -m engine.misra.checker --standards misra,cert,cwe /path/to/source.c

Project-aware analysis

Analyzing a file in isolation produces false positives — unknown types, unexpanded macros and missing headers. Give the checker the build context so it parses code the way the compiler does:

# explicit include paths and defines
python -m engine.misra.checker --standards misra,cert,cwe \
  -I include -I vendor/include -D NDEBUG -D TARGET_ARM=1 \
  src/main.c

# whole project from a compilation database (recommended)
# CMake: cmake -S . -B build -DCMAKE_EXPORT_COMPILE_COMMANDS=ON
# Make:  bear -- make
python -m engine.misra.checker --standards misra,cert,cwe \
  --project build/compile_commands.json

With --project, cppcheck discovers every translation unit and applies each file's own include paths and defines from the database. Results come back in a per-file batch envelope. Flags: -I/--include, -D/--define, -U/--undefine, --std (e.g. c11), --platform (e.g. unix64).

In CI, the GitHub Action exposes the same via project, includes, defines and standards inputs — see gh-action/examples/project.yml.

Baseline mode (adopt on a legacy codebase)

A repo with thousands of pre-existing violations is unusable if every PR shows all of them. Freeze the current state once, then fail only on new violations:

# 1. capture today's violations and commit the file
python -m engine.misra.checker --standards misra,cert,cwe \
  --project build/compile_commands.json \
  --write-baseline .provadyne-baseline.json

# 2. later runs report (and exit non-zero on) only NEW violations
python -m engine.misra.checker --standards misra,cert,cwe \
  --project build/compile_commands.json \
  --baseline .provadyne-baseline.json

Fingerprints are line-number independent (file + rule + normalized source line), so unrelated edits elsewhere don't resurrect baselined findings. The filtered output carries a baseline block (baselined / new counts), and the exit code reflects new violations only. In CI, set the Action's baseline input — see gh-action/examples/baseline.yml.

Report formats (--format)

The checker emits native JSON by default. Pass --format (or pipe the JSON through the matching engine.report.* module) to get an alternative view of the same findings:

# SARIF 2.1.0 for GitHub code scanning / IDEs
python -m engine.misra.checker --standards misra,cert,cwe file.c --format sarif

# Self-contained interactive HTML report (no external deps — opens offline)
python -m engine.misra.checker --standards misra,cert,cwe --iso26262 file.c \
  --format html > report.html

The HTML report is a single file (inline CSS/JS, nothing fetched) with summary cards, an ISO 26262-6 rollup, and client-side filtering — group by rule / file / severity, filter by severity and standard, and free-text search. It works for single-file and batch/project runs and surfaces baselines, deviations and rule filters when present. Over the daemon API, request it with "output_format": "html"; SARIF and HTML are not Pro-gated (PDF is).

Localized output (--lang, Pro)

Finding messages, ISO 26262-6 principle titles and the HTML report UI can be localized into Korean, German, Japanese or Chinese (Simplified) — a deterministic, offline catalog (no network, no LLM, no per-run cost):

python -m engine.misra.checker --standards misra,cert,cwe --iso26262 \
  --lang de file.c --format html > bericht.html

The English source is always preserved in message_en (and title_en), so a report stays bilingual and auditable. MISRA messages are keyed by rule id and CERT messages by CERT id; any string without a catalog entry (e.g. a dynamic CWE-only message) falls back to English. Over the daemon API this is the lang field and requires the Pro localization feature — en (the default) is free.

Inline deviations (provadyne-ignore)

MISRA permits deviations when they are deliberate and documented. Record one directly in the source with a comment:

int *p = get_buffer();   // provadyne-ignore[EXP34-C]: p is null-checked by caller
// provadyne-ignore[8.4]: ISR vector table must have external linkage
void isr_handler(void) { /* ... */ }
  • provadyne-ignore — suppress all violations on the target line
  • provadyne-ignore[8.4] / [8.4, EXP34-C] — suppress specific rules (MISRA rule number, CERT id, or CWE-NNN)
  • text after : is the deviation rationale

A comment on its own line applies to the next line; a trailing comment applies to its own line. Suppressed findings are removed from violations and recorded under a deviations list (rule, line, message, reason) — the audit trail MISRA assessors expect. The run reports a suppressed count. Disable with --no-inline-suppress (CLI). Deviations are honored by default in CI.

Rule coverage

"MISRA C:2023 support" is only honest if it's clear which rules are actually detected. The coverage matrix is derived empirically from the cppcheck misra addon — not hand-maintained — and records, per recognised rule, whether the pinned cppcheck version detects it:

# human-readable summary
python -m engine.misra.coverage

# full matrix (one row per rule)
python -m engine.misra.coverage --format markdown

# machine-readable (counts + supported/unsupported lists)
python -m engine.misra.coverage --format json

The raw data lives in engine/misra/coverage.json (derived_from_cppcheck: "2.20.0"). Today: 130 of 133 recognised rules are statically detected; 8.13, 17.4, 17.5 require manual review.

cppcheck version pin

Detected rules and severities are reproducible only against the cppcheck version the matrix and golden tests were validated against — pinned as SUPPORTED_CPPCHECK_VERSION = "2.20.0" in engine/misra/checker.py. Every analysis result carries cppcheck_version and a cppcheck_supported boolean; when the running cppcheck's major.minor differs from the pin, the CLI emits a ::warning:: (surfaced as a GitHub Actions annotation in CI) so drift never passes silently.

ISO 26262-6 linkage

ISO 26262-6:2018 realises part of its software unit-design objectives through coding standards (clause 5/Table 1 — "use of language subsets" and "established coding standards"), and clause 8/Table 6 lists the unit-design principles. The checker can link each finding to the Table 6 principle it bears on, so a report shows which ISO 26262-6 objective a violation works against:

# annotate findings + add an iso_26262 rollup
python -m engine.misra.checker --standards misra,cert,cwe --iso26262 src/main.c

# the principle catalog itself
python -m engine.misra.coverage           # (rule coverage)
python -m engine.misra.iso26262 --format markdown

With --iso26262, every mapped violation gains an iso_26262 block (principle, title, reference) and the result carries an iso_26262 rollup (mapped / unmapped counts and per-principle totals). The daemon exposes the same via an "iso26262": true field on /api/v1/analyze.

This is evidence linkage, not a certification claim: a finding mapped to a principle means the violation works against that objective; clearing it is supporting evidence toward the safety case, not proof of compliance. Findings with no established correspondence (engine/misra/iso26262_map.json) are left unmapped rather than guessed.

Example Response

{
  "file_path": "/path/to/source.c",
  "violations": [
    {
      "rule": "8.7",
      "severity": "required",
      "line": 42,
      "column": 5,
      "message": "Objects should be defined at block scope if only accessed from a single function",
      "suggestion": {
        "original_code": "int32_t global_counter = 0;",
        "fixed_code": "static int32_t global_counter = 0;",
        "explanation": "Add static keyword to limit linkage to this translation unit",
        "confidence": 0.95,
        "diff": "--- a/source.c\n+++ b/source.c\n@@ -42,1 +42,1 @@\n-int32_t global_counter = 0;\n+static int32_t global_counter = 0;"
      }
    }
  ],
  "analyzed_at": "2026-04-28T17:00:00Z",
  "engine_version": "0.1.0",
  "cppcheck_version": "2.20.0",
  "cppcheck_supported": true
}

C++ (experimental, CLI)

C++ analysis runs through a separate clang-tidy backend, selected with --language cpp:

python -m engine.misra.checker --language cpp --standards all src/widget.cpp

It surfaces two recognized C++ standards:

  • CERT C++ — derived mechanically from clang-tidy's cert-* checks.
  • C++ Core Guidelines — from clang-tidy's cppcoreguidelines-* checks.

Standards tokens for C++: cert, cppcg, misra, all (CWE is not emitted by clang-tidy's text output). MISRA C++:2023 is not claimed: clang-tidy does not implement it natively, so the mapping is seeded empty and extended only with verified correspondences (engine/misra/clangtidy_map.json) — positioning, not certified coverage. Requires clang-tidy (LLVM 18) on PATH; a compile_commands.json (project mode) is strongly recommended to avoid false positives. Over the daemon, C++ is selected by the language field (or auto-detected from the file extension) and gated behind the Pro cpp_analysis feature; the browser extension already sends language: cpp for C/C++ files, so clicking MISRA Check on a .cpp file routes to clang-tidy.

Rust (experimental, CLI)

Rust analysis runs through a clippy backend (MIT/Apache — commercially clean), selected with --language rust:

python -m engine.misra.checker --language rust src/main.rs
# or a whole crate:
python -m engine.misra.checker --language rust --project path/to/Cargo.toml

clippy is crate-based, so the target must live in a Cargo package (the backend walks up to the enclosing Cargo.toml). Findings are surfaced under a single rust-clippy standard with the lint name as the rule id (e.g. clippy::needless_return). There is no MISRA/CERT for Rust; the value is the clippy lint set plus the memory-safety guarantees the compiler enforces by construction. ISO 26262 Table 6 mapping is intentionally sparse (Rust findings show as unmapped rather than guessed). Requires cargo + the clippy component (rustup component add clippy). Over the daemon, Rust is reached in project mode ({"project": ".../Cargo.toml", "language": "rust"}), gated behind the Pro rust_analysis feature. The browser-extension snippet flow does not support Rust (clippy needs a crate); the daemon returns 422 for a Rust snippet.

Free vs Pro

Feature Free Pro
Single file analysis Yes Yes
AI fix suggestions Yes Yes
Batch analysis (multiple files) No Yes
PDF report export No Yes
Localized output (ko/de/ja/zh) No Yes