Skip to content

fix(scripts): make lint-cppcheck-dash actually report warnings - #7535

Merged
PastaPastaPasta merged 17 commits into
dashpay:developfrom
PastaPastaPasta:claude/mystifying-gauss-adccbd
Aug 8, 2026
Merged

fix(scripts): make lint-cppcheck-dash actually report warnings#7535
PastaPastaPasta merged 17 commits into
dashpay:developfrom
PastaPastaPasta:claude/mystifying-gauss-adccbd

Conversation

@PastaPastaPasta

@PastaPastaPasta PastaPastaPasta commented Aug 3, 2026

Copy link
Copy Markdown
Member

Issue being fixed or feature implemented

test/lint/lint-cppcheck-dash.py has been effectively vacuous — it ran cppcheck, silently analyzed almost nothing, and always passed. Two failure modes:

  1. With the script's -D list, __GNUC__ is not defined, so src/attributes.h hits #error No known always_inline attribute (preprocessorErrorDirective), aborting cppcheck's analysis of nearly every translation unit. The error lines were then dropped by the output filter, which only keeps lines pointing at files from test/util/data/non-backported.txt.
  2. Even with preprocessing fixed, cppcheck 2.17.1 with --check-level=exhaustive crashes with an assertion in TokenList::setLang (child dies with signal 6) — and that crash message was explicitly listed in SUPPRESSED_WARNINGS.

Net effect: an injected canary warning in a non-backported file was not flagged, locally or in CI.

What was done?

Linter (test/lint/lint-cppcheck-dash.py):

  • Define __GNUC__ so preprocessing succeeds.
  • Add a FATAL_ERRORS list (preprocessorErrorDirective, syntaxError, internal errors/crashes) that fails the lint regardless of which file the line points at, so analysis failures can never again be silently filtered away. Making syntaxError fatal immediately surfaced real cases: QT_VERSION_CHECK and QT_CONFIG are function-like macros cppcheck cannot evaluate on its own, which aborted analysis of Qt translation units (especially in working trees with uic-generated headers like ui_masternodelist.h) — they are now defined on the cppcheck command line (-DQT_VERSION_CHECK=..., -DQT_CONFIG(x)=0).
  • Fail on any nonzero cppcheck exit status. Without --error-exitcode, diagnostics never make cppcheck return nonzero, so a nonzero status always means the analysis itself failed (bad arguments, unloadable config, OOM kill, crash) and cannot be allowed to pass.
  • Drop the signal-6 crash suppression (the TODO said to remove it with a newer cppcheck).
  • Skip note:/source-context lines: they don't carry the check id that suppressions match on, so orphaned notes of suppressed warnings leaked through the filter.
  • Suppress pre-existing violations so the linter can be enforced now, documented as a burn-down TODO. Most suppressions are deliberately narrow — targeted message/class-scoped regexes for knownConditionTrueFalse (always-false state.Invalid(...)/state.Error(...) returns), shadowFunction (the _ translation function), and uninitMemberVarNoCtor (ActiveDKG/UtilParameters members) — so new violations of these checks elsewhere in the tree are still reported. duplInheritedMember and useStlAlgorithm are suppressed wholesale by check id: the former as a plain burn-down entry, the latter deliberately — earlier revisions of this branch rewrote the flagged raw loops into std::ranges algorithms, but lambda-based algorithms lose Clang thread-safety-analysis lock context (cs_wallet, cs_coinjoin, cs_store) and obscure otherwise-clear control flow, so the loops stay and the check is disabled instead. Messages matching ALWAYS_ENABLED_WARNINGS still override these suppressions.

Container (contrib/containers/ci/ci-slim.Dockerfile): bump cppcheck 2.17.1 → 2.21.0, which no longer crashes under --check-level=exhaustive.

Code fixes for the ~11 warnings that ALWAYS_ENABLED_WARNINGS patterns force-report (these cannot be suppressed by check id): removed dead locals (src/active/dkgsession.cpp, src/rpc/evo.cpp), made single-argument constructors explicit (chainlock::Chainlocks, CDSTXManager; no implicit-conversion call sites exist), inline-suppressed CBLSIdImplicit's intentionally implicit constructor, narrowed three static benchmark counters to their usage scope in src/evo/specialtxman.cpp (static storage duration unchanged), passed CSigBase by const reference in InitSession (callers already sliced identically by value; accessors are non-virtual), moved BlsCheck's by-value constructor parameters into members, and bound the temporary RPCResult returned by GetVotesJsonHelp to a local variable in src/rpc/governance.cpp (avoiding a C++20 dangling reference).

How Has This Been Tested?

With cppcheck 2.21.0 locally (matching the bumped container version):

  • Injected a canary (unreadVariable) into src/spork.cpp: the linter reports exactly that warning and exits 1.
  • Canary removed: full 273-file run is clean and exits 0 (tested both clean and built working trees).
  • Removed -D__GNUC__ to simulate failure mode 1: the attributes.h #error line surfaces via FATAL_ERRORS and the linter exits 1.
  • All touched translation units pass clang -fsyntax-only with the project's compile flags; test/lint/lint-python.py passes.

Note: the previously-suppressed count_if/find_if useStlAlgorithm variants are now covered by the wholesale id suppression along with the rest of the burn-down list.

Breaking Changes

None. CI lint may take somewhat longer since cppcheck now actually analyzes all 273 non-backported files with --check-level=exhaustive.

Checklist:

  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have added or updated relevant unit/integration/functional/e2e tests
  • I have made corresponding changes to the documentation
  • I have assigned this pull request to a milestone (for repository code-owners and collaborators only)

Loading
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants