diff options
| author | Claude <[email protected]> | 2026-06-05 07:27:50 +0000 |
|---|---|---|
| committer | Claude <[email protected]> | 2026-06-05 07:27:50 +0000 |
| commit | de756315ec43bdca54599a7d0ba772fa7fbf7cf6 (patch) | |
| tree | ee1488d54cf8cf721bc5efc545715f8c2b60c3bf | |
| parent | ddc065dc9fd929fcc94b0993c3af4b56877b1cd6 (diff) | |
Add pvs skill to run PVS-Studio analysis for a board
Bundle a run_pvs.sh helper (takes BOARD as its first argument) that
follows the PVS-Studio static-analysis flow from AGENTS.md: build all
examples with an exported compile_commands.json, run pvs-studio-analyzer
against .PVS-Studio/.pvsconfig, then emit errorfile + SARIF reports.
https://claude.ai/code/session_015inWmFhRYSq17CxMukdoqX
| -rw-r--r-- | .claude/skills/pvs/SKILL.md | 74 | ||||
| -rwxr-xr-x | .claude/skills/pvs/run_pvs.sh | 82 |
2 files changed, 156 insertions, 0 deletions
diff --git a/.claude/skills/pvs/SKILL.md b/.claude/skills/pvs/SKILL.md new file mode 100644 index 000000000..cde453d9a --- /dev/null +++ b/.claude/skills/pvs/SKILL.md @@ -0,0 +1,74 @@ +--- +name: pvs +description: Use when running PVS-Studio static analysis (SAST + MISRA C:2023 / C++:2008) on TinyUSB for a given board. Wraps building the examples with an exported compile_commands.json and running pvs-studio-analyzer against .PVS-Studio/.pvsconfig, then converts the log to readable + SARIF output. +--- + +# PVS-Studio Static Analysis + +Run PVS-Studio on TinyUSB for one board. The skill bundles `run_pvs.sh`, which +follows the "Static Analysis (PVS-Studio)" section of AGENTS.md / CLAUDE.md: +build all examples for the board with `compile_commands.json` exported, run +`pvs-studio-analyzer` against it using `.PVS-Studio/.pvsconfig`, then convert the +log to an `errorfile` view and a SARIF report. + +## Quick start + +```bash +# Whole project for a board: +.claude/skills/pvs/run_pvs.sh raspberry_pi_pico + +# Specific files only — -S takes a plaintext list (one path per line), NOT a +# source file directly (the AGENTS.md "-S src/foo.c" snippet is inaccurate): +printf 'src/tusb.c\nsrc/class/cdc/cdc_device.c\n' > /tmp/files.txt +.claude/skills/pvs/run_pvs.sh stm32f407disco -S /tmp/files.txt +``` + +The first positional argument is **BOARD** (required). Everything after it is +forwarded verbatim to `pvs-studio-analyzer analyze`. + +## What the script does + +1. **License** — if no license file is registered, materializes one from the + `PVS_STUDIO_CREDENTIALS` env var (`<name> <key>`, same secret CI uses). +2. **Build** — `cmake examples -B examples/cmake-build-<board> -G Ninja + -DBOARD=<board> -DCMAKE_BUILD_TYPE=MinSizeRel -DCMAKE_EXPORT_COMPILE_COMMANDS=ON` + then `cmake --build`. The exported `compile_commands.json` is what PVS reads. +3. **Analyze** — `pvs-studio-analyzer analyze -f <compile_db> + -R .PVS-Studio/.pvsconfig -o pvs-<board>.log -j<nproc> + --misra-c-version 2023 --misra-cpp-version 2008 --use-old-parser`. + (AGENTS.md shows `--dump-files`; it's omitted because it scatters + `.PVS-Studio.i/.cfg` dumps across the tree — only useful for debugging FPs.) +4. **Report** — `plog-converter -a GA:1,2 -t errorfile` (printed) and + `-t sarif` → `pvs-<board>.sarif`. + +`.PVS-Studio/.pvsconfig` already excludes vendored code (`lib/`, `hw/mcu/`, +`pico-sdk/`, `esp-idf/`, IAR runtime) and suppresses the project's accepted +MISRA deviations — don't duplicate those excludes on the command line. + +## Choosing a board + +Match the build prerequisites (same as the rest of the repo): + +- `raspberry_pi_pico` — what CI's PVS-Studio job uses (needs Pico SDK deps). +- `stm32f407disco` — no external SDK; fastest to get a clean compile DB. +- Anything under `hw/bsp/<family>/boards/` works if its deps are fetched + (`python3 tools/get_deps.py -b <board>`). + +## Outputs + +- `pvs-<board>.log` — raw analyzer log (input to plog-converter). +- `pvs-<board>.sarif` — SARIF report (same format CI uploads). +- errorfile findings are printed to stdout for a quick read. + +## Timing + +Dominated by the example build (tens of seconds to a few minutes depending on +board/deps). The analysis pass itself is ~10-30 s. Use a timeout ≥ 10 minutes +for boards whose deps must be fetched/built first. + +## Reporting results + +After a run, summarize the findings by rule/severity from the errorfile output +and point the user at `pvs-<board>.sarif`. Cross-check anything flagged in +`src/` against `.pvsconfig` — if it's an already-accepted deviation it will have +been suppressed, so surviving findings are genuinely new. diff --git a/.claude/skills/pvs/run_pvs.sh b/.claude/skills/pvs/run_pvs.sh new file mode 100755 index 000000000..3a829327d --- /dev/null +++ b/.claude/skills/pvs/run_pvs.sh @@ -0,0 +1,82 @@ +#!/usr/bin/env bash +# Run PVS-Studio static analysis on TinyUSB for a given BOARD. +# +# Mirrors the "Static Analysis (PVS-Studio)" section in AGENTS.md / CLAUDE.md: +# - build all examples for BOARD with compile_commands.json exported +# - run pvs-studio-analyzer against that compile DB using .PVS-Studio/.pvsconfig +# - convert the log to human-readable (errorfile) and SARIF output +# +# Usage: +# .claude/skills/pvs/run_pvs.sh <BOARD> [extra pvs-studio-analyzer args...] +# +# Examples: +# .claude/skills/pvs/run_pvs.sh raspberry_pi_pico +# # Scope to specific files via a plaintext list (one path per line): +# printf 'src/tusb.c\nsrc/class/cdc/cdc_device.c\n' > /tmp/files.txt +# .claude/skills/pvs/run_pvs.sh stm32f407disco -S /tmp/files.txt +set -euo pipefail + +BOARD="${1:-}" +if [ -z "$BOARD" ]; then + echo "Usage: $0 <BOARD> [extra pvs-studio-analyzer args...]" >&2 + echo "Example: $0 raspberry_pi_pico" >&2 + exit 2 +fi +shift + +REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../../.." && pwd)" +cd "$REPO_ROOT" + +BUILD_DIR="examples/cmake-build-${BOARD}" +COMPILE_DB="${BUILD_DIR}/compile_commands.json" +REPORT_LOG="pvs-${BOARD}.log" +SARIF_OUT="pvs-${BOARD}.sarif" +JOBS="$(nproc 2>/dev/null || echo 4)" + +# --- License --------------------------------------------------------------- +# Use an existing license file, else materialize one from PVS_STUDIO_CREDENTIALS +# (format: "<name> <key>", as supplied by the CI secret of the same name). +if ! pvs-studio-analyzer lic-info >/dev/null 2>&1; then + if [ -n "${PVS_STUDIO_CREDENTIALS:-}" ]; then + echo ">>> Registering PVS-Studio license from PVS_STUDIO_CREDENTIALS" + # shellcheck disable=SC2086 # credentials expects two whitespace-separated args + pvs-studio-analyzer credentials $PVS_STUDIO_CREDENTIALS + else + echo "ERROR: no PVS-Studio license found and PVS_STUDIO_CREDENTIALS is unset." >&2 + exit 1 + fi +fi + +# --- Build (exports compile_commands.json) --------------------------------- +echo ">>> Building all examples for ${BOARD} (this also fetches the compile DB)" +cmake examples -B "${BUILD_DIR}" -G Ninja \ + -DBOARD="${BOARD}" \ + -DCMAKE_BUILD_TYPE=MinSizeRel \ + -DCMAKE_EXPORT_COMPILE_COMMANDS=ON +cmake --build "${BUILD_DIR}" + +if [ ! -f "${COMPILE_DB}" ]; then + echo "ERROR: ${COMPILE_DB} was not produced by the build." >&2 + exit 1 +fi + +# --- Analyze --------------------------------------------------------------- +echo ">>> Running PVS-Studio analyzer (-j${JOBS})" +# Note: AGENTS.md shows --dump-files, but that scatters .PVS-Studio.i/.cfg dump +# files across the source tree (only useful for debugging false positives). It is +# omitted here to keep the working tree clean; add it back via "$@" if needed. +pvs-studio-analyzer analyze \ + -f "${COMPILE_DB}" \ + -R .PVS-Studio/.pvsconfig \ + -o "${REPORT_LOG}" -j"${JOBS}" \ + --misra-c-version 2023 --misra-cpp-version 2008 --use-old-parser \ + "$@" + +# --- Report ---------------------------------------------------------------- +echo ">>> General-analysis + MISRA findings (errorfile):" +plog-converter -a GA:1,2 -t errorfile "${REPORT_LOG}" || true +plog-converter -t sarif -o "${SARIF_OUT}" "${REPORT_LOG}" >/dev/null + +echo ">>> Done." +echo " Raw log : ${REPORT_LOG}" +echo " SARIF : ${SARIF_OUT}" |
