diff options
| author | Ha Thach <[email protected]> | 2026-06-11 23:19:17 +0700 |
|---|---|---|
| committer | GitHub <[email protected]> | 2026-06-11 23:19:17 +0700 |
| commit | 5014146fef1aac07362ee35c0c361b8475f7636d (patch) | |
| tree | 880ae25885c649108a044d185a3b2166d9284079 | |
| parent | 848216a6a278f98ba5b977219adac5eabb07e0c4 (diff) | |
| parent | dd31ba4530f1904b0d2d83fa6b008502354fb400 (diff) | |
Merge pull request #3695 from hathach/claude/adoring-pasteur-kbaFa
Add pvs skill to run PVS-Studio analysis for a board
| -rw-r--r-- | .claude/skills/pvs/SKILL.md | 36 | ||||
| -rwxr-xr-x | .claude/skills/pvs/run_pvs.sh | 85 | ||||
| -rw-r--r-- | .gitignore | 1 | ||||
| -rw-r--r-- | AGENTS.md | 19 |
4 files changed, 135 insertions, 6 deletions
diff --git a/.claude/skills/pvs/SKILL.md b/.claude/skills/pvs/SKILL.md new file mode 100644 index 000000000..bc4bf01bd --- /dev/null +++ b/.claude/skills/pvs/SKILL.md @@ -0,0 +1,36 @@ +--- +name: pvs +description: Use when running PVS-Studio static analysis (SAST + MISRA C:2023 / C++:2008) on TinyUSB for a given board. Builds the examples with an exported compile_commands.json, runs pvs-studio-analyzer against .PVS-Studio/.pvsconfig, and emits readable + SARIF output. +--- + +# PVS-Studio Static Analysis + +`run_pvs.sh <BOARD>` builds all examples for the board (with +`compile_commands.json` exported), runs `pvs-studio-analyzer` against +`.PVS-Studio/.pvsconfig`, then writes `pvs-<board>.log` and `pvs-<board>.sarif` +plus printed errorfile findings. Needs a license file or `$PVS_STUDIO_CREDENTIALS`. + +```bash +.claude/skills/pvs/run_pvs.sh raspberry_pi_pico # whole project for a board + +# Scope to specific files — -S takes a plaintext list (one path per line), +# NOT a source file directly. Extra args pass through to the analyzer. +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 +``` + +## Notes + +- **Board:** `raspberry_pi_pico` mirrors CI (needs Pico SDK deps); + `stm32f407disco` is fastest (no external SDK). Any board works once its deps + are fetched (`python3 tools/get_deps.py -b <board>`). +- `.pvsconfig` already excludes vendored code and suppresses accepted MISRA + deviations — don't re-add those on the command line. Surviving `src/` findings + are genuinely new. +- Timing is dominated by the build (deps may push it past a minute); the analysis + pass is ~10-30 s. Use a timeout ≥ 10 min when deps must be fetched first. +- `--dump-files` is intentionally omitted — it scatters `.PVS-Studio.i/.cfg` + dumps across the tree (FP-debugging only); add it back via the passthrough args. + +After a run, summarize findings by rule/severity from the errorfile output and +point the user at `pvs-<board>.sarif`. diff --git a/.claude/skills/pvs/run_pvs.sh b/.claude/skills/pvs/run_pvs.sh new file mode 100755 index 000000000..7406a3b4f --- /dev/null +++ b/.claude/skills/pvs/run_pvs.sh @@ -0,0 +1,85 @@ +#!/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" + # Split "<name> <key>" into exactly two fields, quoted, so a key containing + # glob chars or extra spaces can't be word-split/expanded. + read -r _pvs_name _pvs_key <<< "$PVS_STUDIO_CREDENTIALS" + pvs-studio-analyzer credentials "$_pvs_name" "$_pvs_key" + 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}" \ + --security-related-issues \ + --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}" diff --git a/.gitignore b/.gitignore index 0f3c9ce49..8fe09e65f 100644 --- a/.gitignore +++ b/.gitignore @@ -12,6 +12,7 @@ hil_report.json *.env *.ind *.log +*.sarif *.map *.obj *.jlink @@ -153,28 +153,35 @@ Reports land in `cmake-metrics/<board>/metrics_compare.md` (per-board) and `cmak ## Static Analysis (PVS-Studio) -Requires `compile_commands.json` (CMake `-DCMAKE_EXPORT_COMPILE_COMMANDS=ON`). +Requires `compile_commands.json`, which the examples build exports by default +(`hw/bsp/family_support.cmake` sets `CMAKE_EXPORT_COMPILE_COMMANDS ON`). The +`pvs` skill (`.claude/skills/pvs/SKILL.md`) wraps the build + analyze flow for a +board; the commands below are the underlying steps. ```bash # Whole project: pvs-studio-analyzer analyze \ -f examples/cmake-build-raspberry_pi_pico/compile_commands.json \ -R .PVS-Studio/.pvsconfig \ - -o pvs-report.log -j12 --dump-files \ + -o pvs-report.log -j12 \ + --security-related-issues \ --misra-c-version 2023 --misra-cpp-version 2008 --use-old-parser -# Specific files (add one or more `-S <file>`): +# Specific files: -S takes a plaintext list (one path per line), not paths directly: +printf 'src/foo.c\nsrc/bar.c\n' > files.txt pvs-studio-analyzer analyze \ -f examples/cmake-build-raspberry_pi_pico/compile_commands.json \ -R .PVS-Studio/.pvsconfig \ - -S src/foo.c -S src/bar.c \ - -o pvs-report.log -j12 --dump-files \ + -S files.txt \ + -o pvs-report.log -j12 \ + --security-related-issues \ --misra-c-version 2023 --misra-cpp-version 2008 --use-old-parser plog-converter -a GA:1,2 -t errorfile pvs-report.log # view results ``` -Takes ~10-30 s. +Takes ~10-30 s. (`--dump-files` adds preprocessed `.PVS-Studio.i/.cfg` dumps next +to every source for false-positive debugging — omit it for normal runs.) ## Validation After Changes |
