Skip to content

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

Open
PastaPastaPasta wants to merge 15 commits into
dashpay:developfrom
PastaPastaPasta:claude/mystifying-gauss-adccbd
Open

fix(scripts): make lint-cppcheck-dash actually report warnings#7535
PastaPastaPasta wants to merge 15 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 a real case: QT_VERSION_CHECK is a function-like macro cppcheck cannot evaluate, which aborted analysis of the Qt translation units — it is now defined on the cppcheck command line.
  • 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 inline-suppressed a danglingTempReference false positive on a lifetime-extended range-for temporary in src/rpc/governance.cpp.

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.
  • 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)

@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

The pull request updates cppcheck tooling and suppressions, replaces manual loops with C++20 ranges algorithms, adds explicit default initialization, and marks overridden destructors. It also simplifies APIs by removing unused parameters, adding static and const qualifiers, changing unnecessary copies to references or moves, and updating governance, index, RPC, wallet, and UI call sites.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Possibly related PRs

  • dashpay/dash#7052: Both changes modify CoinJoin client and server code.
  • dashpay/dash#7456: Both changes modify EvoDB and chainstate-related interfaces.
  • dashpay/dash#7471: Both changes remove the ChainstateManager parameter from RecalculateAndRepairDiffs.

Suggested reviewers: udjinm6

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 16.81% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly identifies the main change: updating lint-cppcheck-dash to report warnings instead of silently passing.
Description check ✅ Passed The description directly explains the linter fixes, cppcheck update, warning cleanup, and validation performed.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

@thepastaclaw

thepastaclaw commented Aug 3, 2026

Copy link
Copy Markdown

✅ Final review complete — no blockers (commit 9303de4)

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 53576af0a1

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +141 to +143
if re.search(fatal_regexp, line):
warnings.append(line)
continue

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Fail when cppcheck exits unsuccessfully

When cppcheck is killed (for example by OOM during the exhaustive parallel run) or encounters another failure whose output lacks these four strings, dependencies_output.returncode is ignored and warnings can remain empty, so the linter exits successfully without analyzing anything. This is the same vacuous-success mode the change intends to prevent; I reproduced it with a fake cppcheck that exits 137 with no output, for which this script returned 0. Treat any nonzero subprocess return code as a lint failure in addition to parsing fatal diagnostics.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 5562094 — any nonzero cppcheck exit status now fails the lint unconditionally (no --error-exitcode is passed, so diagnostics never produce a nonzero status; every nonzero status is an analysis failure).


🤖 Posted autonomously by Claude on behalf of pasta.

@github-actions

github-actions Bot commented Aug 3, 2026

Copy link
Copy Markdown

This pull request has conflicts, please rebase.

@PastaPastaPasta PastaPastaPasta changed the title fix(lint): make lint-cppcheck-dash actually report warnings fix(scripts): make lint-cppcheck-dash actually report warnings Aug 3, 2026

@thepastaclaw thepastaclaw left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Preliminary review — Codex only

The cppcheck preprocessing fix, version upgrade, warning filtering, and associated warning cleanups appear sound. However, the linter still ignores cppcheck's process exit status, so analyzer failures outside the small recognized-message list can silently pass, contradicting the PR's goal of preventing vacuous analysis.

Validated blockers were found in the Codex precheck. Sonnet is deferred until a fresh Codex revalidation clears the blocker gate.

Review provenance

  • Codex reviewers: gpt-5.6-sol — general (completed), gpt-5.6-sol — dash-core-commit-history (completed)
  • Verifier: gpt-5.6-sol — verifier
  • Sonnet: not run (deferred by blocker gate)

🔴 1 blocking

1 additional finding(s) omitted (not in diff).

🤖 Prompt for all review comments with AI agents
These findings are from an automated code review. Verify each finding against the current code and only fix it if needed.

In `test/lint/lint-cppcheck-dash.py`:
- [BLOCKING] test/lint/lint-cppcheck-dash.py:132-137: Nonzero cppcheck exits still pass the lint
  The completed process's `returncode` is never checked. A top-level cppcheck failure that does not emit one of the four recognized `FATAL_ERRORS` strings—such as SIGKILL/OOM, an assertion with different wording, a configuration-loading failure, or an unsupported option—is filtered out and the script exits successfully when no recognized warnings remain. This was reproduced with a cppcheck shim that prints `cppcheck: error: failed to load configuration` and exits 2; the linter exits 0. Because ordinary cppcheck findings do not produce a nonzero status unless `--error-exitcode` is configured, failing on any nonzero status preserves the existing warning filtering while ensuring analyzer failures cannot silently pass.

@github-actions

github-actions Bot commented Aug 3, 2026

Copy link
Copy Markdown

Potential PR merge conflicts

This is advisory only. It does not block CI, but it marks PRs that will likely need a rebase depending on merge order.

If these PRs merge first

This PR will likely need a rebase:

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/rpc/blockchain.cpp`:
- Line 568: Update TimestampIndex::ReadRange and GetBlockHashes to return a
boolean success status, propagating pcursor->Status() failures instead of
silently using partial blockHashes. In the getblockhashes RPC flow around
g_timestampindex->GetBlockHashes, check the returned status and raise
RPC_MISC_ERROR before constructing the successful result.

In `@test/lint/lint-cppcheck-dash.py`:
- Around line 128-132: Update the diagnostic filter in the cppcheck parsing
logic to retain the supported non-noise severities: error, warning, style,
performance, and portability. Continue discarding information, note, and
source-context lines before suppression matching.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: cdb36e58-3397-4802-b0c9-cff23cdeb7a0

📥 Commits

Reviewing files that changed from the base of the PR and between 0017f50 and d802b17.

📒 Files selected for processing (88)
  • contrib/containers/ci/ci-slim.Dockerfile
  • src/active/context.h
  • src/active/dkgsession.cpp
  • src/active/dkgsession.h
  • src/active/dkgsessionhandler.h
  • src/bench/bls_dkg.cpp
  • src/bls/bls.cpp
  • src/bls/bls.h
  • src/bls/bls_worker.cpp
  • src/chainlock/chainlock.h
  • src/chainlock/signing.cpp
  • src/chainlock/signing.h
  • src/coinjoin/client.cpp
  • src/coinjoin/client.h
  • src/coinjoin/coinjoin.cpp
  • src/coinjoin/coinjoin.h
  • src/coinjoin/common.h
  • src/coinjoin/server.cpp
  • src/coinjoin/server.h
  • src/coinjoin/util.cpp
  • src/coinjoin/util.h
  • src/coinjoin/walletman.cpp
  • src/evo/core_write.cpp
  • src/evo/deterministicmns.cpp
  • src/evo/deterministicmns.h
  • src/evo/dmn_types.h
  • src/evo/mnhftx.h
  • src/evo/netinfo.cpp
  • src/evo/netinfo.h
  • src/evo/providertx.cpp
  • src/evo/simplifiedmns.cpp
  • src/evo/smldiff.cpp
  • src/evo/specialtxman.cpp
  • src/governance/governance.cpp
  • src/governance/governance.h
  • src/governance/net_governance.cpp
  • src/governance/signing.cpp
  • src/governance/superblock.cpp
  • src/governance/superblock.h
  • src/index/addressindex.cpp
  • src/index/addressindex.h
  • src/index/addressindex_types.h
  • src/index/timestampindex.cpp
  • src/index/timestampindex.h
  • src/init.cpp
  • src/instantsend/instantsend.h
  • src/instantsend/signing.cpp
  • src/instantsend/signing.h
  • src/llmq/commitment.cpp
  • src/llmq/core_write.cpp
  • src/llmq/debug.cpp
  • src/llmq/dkgmessages.h
  • src/llmq/dkgsessionmgr.h
  • src/llmq/ehf_signals.h
  • src/llmq/net_dkg.cpp
  • src/llmq/net_dkg.h
  • src/llmq/net_quorum.cpp
  • src/llmq/net_quorum.h
  • src/llmq/net_signing.cpp
  • src/llmq/observer.h
  • src/llmq/params.h
  • src/llmq/quorums.h
  • src/llmq/signing_shares.cpp
  • src/llmq/signing_shares.h
  • src/llmq/snapshot.h
  • src/llmq/utils.cpp
  • src/masternode/meta.h
  • src/node/interfaces.cpp
  • src/qt/clientfeeds.h
  • src/qt/donutchart.h
  • src/rpc/blockchain.cpp
  • src/rpc/coinjoin.cpp
  • src/rpc/evo.cpp
  • src/rpc/governance.cpp
  • src/rpc/masternode.cpp
  • src/rpc/quorums.cpp
  • src/stacktraces.cpp
  • src/stats/client.cpp
  • src/test/evo_netinfo_tests.cpp
  • src/test/util/llmq_tests.h
  • src/util/ranges_set.cpp
  • src/util/ranges_set.h
  • src/util/std23.h
  • src/wallet/bip39.cpp
  • src/wallet/coinjoin.cpp
  • src/wallet/hdchain.cpp
  • src/wallet/hdchain.h
  • test/lint/lint-cppcheck-dash.py
💤 Files with no reviewable changes (2)
  • src/governance/net_governance.cpp
  • src/active/dkgsession.cpp

Comment thread src/rpc/blockchain.cpp Outdated
Comment thread test/lint/lint-cppcheck-dash.py
@PastaPastaPasta
PastaPastaPasta force-pushed the claude/mystifying-gauss-adccbd branch from d802b17 to b44f9e3 Compare August 3, 2026 21:45

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b44f9e3217

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

# These must always fail the lint (regardless of which file they point at),
# otherwise analysis silently ends up vacuous.
FATAL_ERRORS = (
"preprocessorErrorDirective",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Treat parser syntax errors as fatal

When cppcheck aborts a translation unit with an error such as src/validation.h:...: error: syntax error [syntaxError], this list does not classify it as fatal, and the later file filter discards it because the included header is outside non-backported.txt. The linter can therefore pass after cppcheck skipped analysis of one or more targeted files; include syntaxError and other analysis-abort diagnostics in the path-independent fatal set.

AGENTS.md reference: AGENTS.md:L48-L50

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 5562094syntaxError is now in the path-independent FATAL_ERRORS set. It immediately caught a real instance (QT_VERSION_CHECK aborting Qt translation units via src/qt/guiutil.h), fixed by defining the macro on the cppcheck command line.


🤖 Posted autonomously by Claude on behalf of pasta.

@thepastaclaw thepastaclaw left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Preliminary review — Codex only

Two in-scope blockers remain at exact head b44f9e3. PF-1 is still valid because cppcheck's process status is ignored; separately, the latest suppression burn-down re-enables useStlAlgorithm while the diagnostic filter discards its style-severity output, so the check is not actually enforced.

Validated blockers were found in the Codex precheck. Sonnet is deferred until a fresh Codex revalidation clears the blocker gate.

Review provenance

  • Codex reviewers: gpt-5.6-sol — general (completed), gpt-5.6-sol — dash-core-commit-history (completed)
  • Verifier: gpt-5.6-sol — verifier
  • Sonnet: not run (deferred by blocker gate)

🔴 2 blocking

1 additional finding(s) omitted (not in diff).

🤖 Prompt for all review comments with AI agents
These findings are from an automated code review. Verify each finding against the current code and only fix it if needed.

In `test/lint/lint-cppcheck-dash.py`:
- [BLOCKING] test/lint/lint-cppcheck-dash.py:122-127: Nonzero cppcheck exits still pass the lint
  The completed process is captured, but dependencies_output.returncode is never inspected. FATAL_ERRORS only catches four textual markers, so a command-line/configuration failure, crash, OOM termination, or other unsuccessful cppcheck exit can produce no retained warning and let the script exit successfully without completing analysis. This reproduces on the current head with a cppcheck shim that exits 2 after version detection: lint-cppcheck-dash.py exits 0. Because the command does not use --error-exitcode, ordinary diagnostics do not make cppcheck return nonzero, so every nonzero process status can safely be treated as an analyzer failure.
- [BLOCKING] test/lint/lint-cppcheck-dash.py:134-138: The diagnostic filter discards cppcheck style findings
  The GCC-formatted output filter retains only error and warning severities. Cppcheck classifies both unreadVariable and the useStlAlgorithm check re-enabled by the head commit as style, so these diagnostics are discarded before the allowlist and suppression logic runs. A current-head shim emitting a style-severity unreadVariable diagnostic for a targeted file makes the script exit 0, and cppcheck's error list confirms that useStlAlgorithm and unreadVariable have style severity. Performance and portability findings enabled by --enable=all are also silently discarded.

Comment on lines +134 to +138
# 'note:' and source-context lines only make sense next to their parent
# warning; on their own (e.g. when the parent is suppressed) they are
# noise, and they don't carry the check id the suppressions match on.
if ' warning: ' not in line and ' error: ' not in line:
continue

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 Blocking: The diagnostic filter discards cppcheck style findings

The GCC-formatted output filter retains only error and warning severities. Cppcheck classifies both unreadVariable and the useStlAlgorithm check re-enabled by the head commit as style, so these diagnostics are discarded before the allowlist and suppression logic runs. A current-head shim emitting a style-severity unreadVariable diagnostic for a targeted file makes the script exit 0, and cppcheck's error list confirms that useStlAlgorithm and unreadVariable have style severity. Performance and portability findings enabled by --enable=all are also silently discarded.

Suggested change
# 'note:' and source-context lines only make sense next to their parent
# warning; on their own (e.g. when the parent is suppressed) they are
# noise, and they don't carry the check id the suppressions match on.
if ' warning: ' not in line and ' error: ' not in line:
continue
# Keep primary diagnostics while discarding information, notes, and source context.
if not re.search(r' (?:error|warning|style|performance|portability): ', line):
continue

source: ['codex']

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Widened the filter to r' (?:error|warning|style|performance|portability): ' in 5562094.

One correction to the finding, for the record: cppcheck's --template=gcc hardcodes the severity label, rendering every non-error severity as warning: — verified locally with cppcheck 2.21.0, where a style-severity unreadVariable canary prints as warning: Variable 'x' is assigned a value that is never used. [unreadVariable]. So real cppcheck output was not being dropped (which is also why the PR's canary test reported correctly); the shim repro emits a line format real cppcheck does not produce with this template. The widened match is still worth having as insurance against template changes, so it's in.


🤖 Posted autonomously by Claude on behalf of pasta.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resolved in this update — The diagnostic filter discards cppcheck style findings no longer present.

Auto-resolved by the review system based on the latest commit diff. If you believe this was closed in error, reopen the thread.

@github-actions

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown

This pull request has conflicts, please rebase.

@PastaPastaPasta
PastaPastaPasta force-pushed the claude/mystifying-gauss-adccbd branch from b44f9e3 to 97e975e Compare August 4, 2026 05:18

@thepastaclaw thepastaclaw left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Preliminary review — Codex only

At exact head 97e975e, both carried-forward blockers remain reproducible: nonzero cppcheck exits can pass, and style diagnostics are discarded before suppression handling. No genuinely new latest-delta findings were identified; the timestamp-index hardening suggested by CodeRabbit concerns behavior that already existed at the PR base and is outside this lint-focused change.

Validated blockers were found in the Codex precheck. Sonnet is deferred until a fresh Codex revalidation clears the blocker gate.

Review provenance

  • Codex reviewers: gpt-5.6-sol — general (completed), gpt-5.6-sol — dash-core-commit-history (completed)
  • Verifier: gpt-5.6-sol — verifier
  • Sonnet: not run (deferred by blocker gate)

🔴 2 blocking

1 additional finding(s) omitted (not in diff).

1 carried-forward finding(s) already raised on this PR; not re-posting as new inline comments.

🤖 Prompt for all review comments with AI agents
These findings are from an automated code review. Verify each finding against the current code and only fix it if needed.

In `test/lint/lint-cppcheck-dash.py`:
- [BLOCKING] test/lint/lint-cppcheck-dash.py:122-127: Nonzero cppcheck exits still pass the lint
  The completed cppcheck process is captured, but its return code is never checked. An analyzer crash, invalid invocation, OOM termination, or other unsuccessful exit can therefore pass whenever its output does not match one of the four FATAL_ERRORS patterns and survive the later file/severity filters. At the current head, a shim that succeeds for `--version`, prints an unrecognized configuration error, and exits 2 makes this linter exit 0. Because the command does not set `--error-exitcode`, ordinary cppcheck diagnostics retain the default zero status, so treating every nonzero status as an analyzer failure does not conflate findings with execution failures.

@knst knst left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see multiple comments

Comment thread src/bls/bls.h
{
CBLSIdImplicit() = default;
// cppcheck-suppress noExplicitConstructor
CBLSIdImplicit(const uint256& id)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why don't add explicit here? any good reason for it?
Fix is trivial:

diff --git a/src/bls/bls.cpp b/src/bls/bls.cpp
index 49981ee919..884523fb47 100644
--- a/src/bls/bls.cpp
+++ b/src/bls/bls.cpp
@@ -27,7 +27,7 @@ static const std::unique_ptr<bls::CoreMPL>& Scheme(const bool fLegacy)
 
 CBLSId::CBLSId(const uint256& nHash) : CBLSWrapper<CBLSIdImplicit, BLS_CURVE_ID_SIZE, CBLSId>()
 {
-    impl = nHash;
+    impl = CBLSIdImplicit{nHash};
     fValid = true;
     cachedHash.SetNull();
 }
diff --git a/src/bls/bls.h b/src/bls/bls.h
index 02a3bbefa5..dba9f198a2 100644
--- a/src/bls/bls.h
+++ b/src/bls/bls.h
@@ -234,7 +234,7 @@ public:
 struct CBLSIdImplicit : public uint256
 {
     CBLSIdImplicit() = default;
-    CBLSIdImplicit(const uint256& id)
+    explicit CBLSIdImplicit(const uint256& id)
     {
         memcpy(begin(), id.begin(), sizeof(uint256));
     }

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deferring making CBLSIdImplicit explicit to a follow-up PR. The intentional implicit conversion is still used at the CBLSId construction site (impl = nHash), and tightening that is a small but separate API-style change that can be done with its own call-site audit.

Comment thread src/rpc/governance.cpp
auto ret = CGovernanceObject::GetStateJsonHelp(/*key=*/"", /*optional=*/false, /*local_valid_key=*/"fBlockchainValidity");
auto mod_inner = ret.m_inner;
for (const auto& result : CGovernanceObject::GetVotesJsonHelp(/*key=*/"", /*optional=*/false).m_inner) {
// The range expression's temporary is lifetime-extended for the whole loop

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't it safe for C++23 only? See proposal P2718

Should be fixed instead suppressed then.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed — the lifetime-extension of a range-for temporary is only guaranteed by P2718/C++23. That path is no longer relying on the temporary: useStlAlgorithm stores the helper result in a named local (votes_help) and iterates that, so no suppression is needed anymore.

Comment thread src/llmq/signing_shares.cpp Outdated

{
auto& db = sigman.GetDb();
auto& db = signing_manager.GetDb();

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

auto& db = sigman.GetDb();
auto& db = signing_manager.GetDb();

how exactly it works? It seems as some changes for lint: re-enable shadowMember cppcheck wrongly squashed to other commit.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch. That was a bad leftover from the shadowMember re-enable after #7539 dropped the CSigningManager parameter — there is no signing_manager parameter anymore, so this must use the member sigman. Fixed in 4c40ab4.

Comment thread src/coinjoin/server.cpp Outdated
if (!opt_dsq.has_value()) return false;

connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::DSQUEUE, *opt_dsq));
connman_in.PushMessage(&pfrom, msgMaker.Make(NetMsgType::DSQUEUE, *opt_dsq));

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how exactly it works? It seems as some changes for lint: re-enable shadowMember cppcheck wrongly squashed to other commit.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same class of rebase leftover as above: after #7538 dropped the CConnman parameter from ProcessGetData, the body incorrectly still referenced connman_in. Restored the member connman in 4c40ab4 (this was also the CI build break).

*/
bool ConfirmInventoryRequest(const CInv& inv)
EXCLUSIVE_LOCKS_REQUIRED(!cs_store);
bool ProcessVoteAndRelay(const CGovernanceVote& vote, CGovernanceException& exception, CConnman& connman)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should remove also class CConnman; forward declaration

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 4c40ab4 — the unused class CConnman; forward declaration is removed from governance.h.

vote.SetSignature(m_mn_activeman.SignBasic(vote.GetSignatureHash()));

CGovernanceException exception;
if (!m_govman.ProcessVoteAndRelay(vote, exception, m_connman)) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should remove member variable CConnman& m_connman; and forward declaration from signing.h also

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 4c40ab4: dropped m_connman (and the constructor parameter / call site in ActiveContext) from GovernanceSigner, since ProcessVoteAndRelay no longer needs a CConnman and the member was unused.

Comment thread src/rpc/governance.cpp Outdated
}

CConnman& connman = EnsureConnman(node);
EnsureConnman(node);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no Connman here is needed at all

-EnsureConnman(node);

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed in 4c40ab4. ProcessVoteAndRelay only queues relay inventory and no longer needs CConnman, so the dead EnsureConnman(node) call is gone.

Comment thread src/rpc/governance.cpp Outdated
CGovernanceException exception;
CConnman& connman = EnsureConnman(node);
if (node.govman->ProcessVoteAndRelay(vote, exception, connman)) {
EnsureConnman(node);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no Connman here is needed at all:

-EnsureConnman(node);

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed in 4c40ab4 as well.

Comment thread src/rpc/evo.cpp
const CBlockIndex* pBaseBlockIndex = ParseBlockIndex(request.params[0], chainman, "baseBlock");
const CBlockIndex* pTargetBlockIndex = ParseBlockIndex(request.params[1], chainman, "block");

if (pBaseBlockIndex == nullptr) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: make ParseBlockIndex to return gsl::non_null to enforce that it won't be null ptr ;

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair nit, but out of scope for this cppcheck burn-down PR. Happy to take gsl::not_null for ParseBlockIndex in a follow-up if we want to enforce the post-condition more strongly.

@PastaPastaPasta
PastaPastaPasta force-pushed the claude/mystifying-gauss-adccbd branch 3 times, most recently from c442a20 to 2d8bc46 Compare August 4, 2026 22:40

@thepastaclaw thepastaclaw left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Preliminary review — Codex only

At exact head 2d8bc46, the current tree repairs the obvious rebase compile failures, but the cppcheck linter can still succeed after failed or incomplete analysis: both prior blockers remain reproducible, and syntax failures reported against non-target headers are also discarded. The final repair commit also leaves seven preceding commits unbuildable, so the stack should be rewritten before merge.

Validated blockers were found in the Codex precheck. Sonnet is deferred until a fresh Codex revalidation clears the blocker gate.

Review provenance

  • Codex reviewers: gpt-5.6-sol — general (completed), gpt-5.6-sol — dash-core-commit-history (completed)
  • Verifier: gpt-5.6-sol — verifier
  • Sonnet: not run (deferred by blocker gate)

🔴 4 blocking

1 additional finding(s) omitted (not in diff).

1 carried-forward finding(s) already raised on this PR; not re-posting as new inline comments.

🤖 Prompt for all review comments with AI agents
These findings are from an automated code review. Verify each finding against the current code and only fix it if needed.

In `test/lint/lint-cppcheck-dash.py`:
- [BLOCKING] test/lint/lint-cppcheck-dash.py:145-155: Nonzero cppcheck exits still pass the lint
  The new return-code check still accepts exit code 1 whenever cppcheck produces nonempty output that is not otherwise parsed as a warning. Cppcheck's own help states that diagnostics return the default status 0 unless `--error-exitcode` is specified, while status 1 indicates invalid arguments or missing inputs. This also reproduces with the installed cppcheck configuration: cppcheck exits 1 because `std.cfg` cannot be loaded, but this linter exits 0. Treat every nonzero analyzer status as a failed analysis.
- [BLOCKING] test/lint/lint-cppcheck-dash.py:39-44: Parser syntax failures are not treated as path-independent fatal errors
  A `syntaxError` means cppcheck could not finish parsing the affected translation unit, but that diagnostic ID is missing from `FATAL_ERRORS`. When the error is attributed to an included header outside the files selected from `non-backported.txt`, the later path filter discards it; without `--error-exitcode`, diagnostics also retain cppcheck's default zero status. A shim emitting `src/validation.h:10:5: error: syntax error [syntaxError]` with status 0 makes the current linter exit 0, contrary to this PR's stated goal of preventing silently vacuous analysis.

In `<commit:2d8bc46e9e9>`:
- [BLOCKING] <commit:2d8bc46e9e9>:1: Fold the rebase-repair commit into the commits it amends
  Commit 422eaba1bb1 changes two accesses to `connman_in` and `signing_manager`, but neither identifier exists in the corresponding function or elsewhere in those files at that commit. As a result, 422eaba1bb1 and the following six commits remain unbuildable until 2d8bc46e9e9 reverses those changes. The final commit also combines that repair with governance cleanup belonging with aac92f4a8fb and cppcheck behavior belonging with b8adc3f03d3. Fold each correction into the commit that introduced or necessitated it so every intermediate commit builds and represents a durable logical change.

Comment thread test/lint/lint-cppcheck-dash.py Outdated
Comment on lines +145 to +155
# cppcheck may die (OOM/assert/signal) without emitting FATAL_ERRORS lines that
# match our filter. Exit codes 0/1 are normal (clean / findings); anything else
# or a nonzero exit with empty output means analysis failed and must not pass.
rc = dependencies_output.returncode
if (rc not in (0, 1) or (rc != 0 and not dependencies_output.stdout.strip())) and not warnings:
print(f"cppcheck exited with code {rc} and produced no parseable diagnostics")
if dependencies_output.stdout:
# Show a short tail to aid CI debugging without flooding logs.
tail = dependencies_output.stdout.splitlines()[-50:]
print('\n'.join(tail))
exit_code = 1

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 Blocking: Nonzero cppcheck exits still pass the lint

The new return-code check still accepts exit code 1 whenever cppcheck produces nonempty output that is not otherwise parsed as a warning. Cppcheck's own help states that diagnostics return the default status 0 unless --error-exitcode is specified, while status 1 indicates invalid arguments or missing inputs. This also reproduces with the installed cppcheck configuration: cppcheck exits 1 because std.cfg cannot be loaded, but this linter exits 0. Treat every nonzero analyzer status as a failed analysis.

Suggested change
# cppcheck may die (OOM/assert/signal) without emitting FATAL_ERRORS lines that
# match our filter. Exit codes 0/1 are normal (clean / findings); anything else
# or a nonzero exit with empty output means analysis failed and must not pass.
rc = dependencies_output.returncode
if (rc not in (0, 1) or (rc != 0 and not dependencies_output.stdout.strip())) and not warnings:
print(f"cppcheck exited with code {rc} and produced no parseable diagnostics")
if dependencies_output.stdout:
# Show a short tail to aid CI debugging without flooding logs.
tail = dependencies_output.stdout.splitlines()[-50:]
print('\n'.join(tail))
exit_code = 1
# Without --error-exitcode, diagnostics do not make cppcheck return nonzero;
# any nonzero status means analysis did not complete successfully.
rc = dependencies_output.returncode
if rc != 0:
print(f"cppcheck exited with code {rc}")
if dependencies_output.stdout and not warnings:
tail = dependencies_output.stdout.splitlines()[-50:]
print('\n'.join(tail))
exit_code = 1

source: ['codex']

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adopted in 5562094: any nonzero cppcheck exit status now fails the lint unconditionally. Since the script does not pass --error-exitcode, diagnostics never produce a nonzero status, so every nonzero status is an analysis failure (bad arguments, unloadable config, OOM kill, crash). Verified with shim cppchecks: exit 1 with a driver error line, exit 1 with no output, and exit 137 with no output all fail the lint now; a clean exit 0 run still passes.


🤖 Posted autonomously by Claude on behalf of pasta.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resolved in this update — Nonzero cppcheck exits still pass the lint no longer present.

Auto-resolved by the review system based on the latest commit diff. If you believe this was closed in error, reopen the thread.

Comment on lines +39 to +44
FATAL_ERRORS = (
"preprocessorErrorDirective",
"cppcheckError",
"internalError",
"Internal error",
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 Blocking: Parser syntax failures are not treated as path-independent fatal errors

A syntaxError means cppcheck could not finish parsing the affected translation unit, but that diagnostic ID is missing from FATAL_ERRORS. When the error is attributed to an included header outside the files selected from non-backported.txt, the later path filter discards it; without --error-exitcode, diagnostics also retain cppcheck's default zero status. A shim emitting src/validation.h:10:5: error: syntax error [syntaxError] with status 0 makes the current linter exit 0, contrary to this PR's stated goal of preventing silently vacuous analysis.

Suggested change
FATAL_ERRORS = (
"preprocessorErrorDirective",
"cppcheckError",
"internalError",
"Internal error",
)
FATAL_ERRORS = (
"preprocessorErrorDirective",
"cppcheckError",
"internalError",
"Internal error",
"syntaxError",
)

source: ['codex']

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adopted in 5562094: syntaxError is now in FATAL_ERRORS. This immediately proved its worth — the full-tree run surfaced src/qt/guiutil.h:529: warning: failed to evaluate #if condition, undefined function-like macro invocation: QT_VERSION_CHECK( ... ) [syntaxError], which was previously discarded by the path filter and silently aborted analysis of the Qt translation units. Fixed the underlying cause by defining QT_VERSION_CHECK(major,minor,patch) on the cppcheck command line; the full 273-file run is clean again.


🤖 Posted autonomously by Claude on behalf of pasta.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resolved in this update — Parser syntax failures are not treated as path-independent fatal errors no longer present.

Auto-resolved by the review system based on the latest commit diff. If you believe this was closed in error, reopen the thread.

@PastaPastaPasta
PastaPastaPasta force-pushed the claude/mystifying-gauss-adccbd branch 2 times, most recently from 3597b13 to a4647b6 Compare August 5, 2026 18:23
@github-actions

github-actions Bot commented Aug 7, 2026

Copy link
Copy Markdown

This pull request has conflicts, please rebase.

The cppcheck linter has been silently analyzing nothing (see next commit), letting several warnings in non-backported files accumulate. Fix the ones that the linter's ALWAYS_ENABLED_WARNINGS patterns force-report: remove unused/dead locals, make single-argument constructors explicit (with an inline suppression for CBLSIdImplicit, whose implicit conversion is intentional), narrow benchmark counters to the scope they are used in, pass CSigBase and BlsCheck constructor arguments by reference/move, and inline-suppress a danglingTempReference false positive on a lifetime-extended range-for temporary.
The linter has been vacuous in two ways. First, without __GNUC__ defined, src/attributes.h hits '#error No known always_inline attribute', which aborts cppcheck's analysis of nearly every translation unit; the resulting preprocessorErrorDirective lines were then dropped by the output filter because they don't point at files from non-backported.txt. Second, even with preprocessing fixed, cppcheck 2.17.1 crashes with an assertion in TokenList::setLang under --check-level=exhaustive, and that crash was explicitly suppressed.

Define __GNUC__ so preprocessing succeeds, bump cppcheck to 2.21.0 (which no longer crashes with exhaustive checking) and drop the crash suppression, and treat analysis failures (preprocessorErrorDirective, syntaxError, internal errors) as lint failures regardless of which file they point at so the linter can never silently go vacuous again. Making syntaxError fatal immediately surfaced a real case: QT_VERSION_CHECK is a function-like macro cppcheck cannot evaluate, which aborted analysis of the Qt translation units, so define it on the command line too.

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 must not pass. Filter out 'note:'/source-context lines, which don't carry the check id that suppressions match on and would leak through when their parent warning is suppressed, while matching all real diagnostic severities (the gcc template currently renders them all as 'warning:', but match the raw severities too in case that changes).

Finally, suppress the check ids with pre-existing violations in the tree so the linter can be enforced; these should be burned down and re-enabled over time.
@PastaPastaPasta
PastaPastaPasta force-pushed the claude/mystifying-gauss-adccbd branch from 4651846 to d7c9105 Compare August 7, 2026 20:26
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@PastaPastaPasta

Copy link
Copy Markdown
Member Author

Rebased on develop 4dfe036 to clear the conflict with #7555: its new IsValid() guard in HasOperatorKeyUnderAnyScheme now sits alongside this PR's inline cppcheck suppression in the same function. Only that one file conflicted; no other changes, full cppcheck lint run clean.


🤖 Posted autonomously by Claude on behalf of pasta.

@PastaPastaPasta
PastaPastaPasta force-pushed the claude/mystifying-gauss-adccbd branch from d7c9105 to 9303de4 Compare August 7, 2026 21:37
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@thepastaclaw thepastaclaw left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Final validation — Codex + Sonnet

At exact head 9303de4, all four cppcheck-linter correctness gaps from prior review rounds are genuinely fixed and independently reverified: nonzero cppcheck exit codes unconditionally fail the lint (no exception for unrecognized-error text), the diagnostic-severity filter retains error/warning/style/performance/portability lines, syntaxError is a path-independent fatal error, and the 15-commit history contains no rebase-repair, introduce-then-rollback, or leftover-identifier commits (verified connman_in/signing_manager/stray CConnman forward declarations are all absent from the tree). The BLS Span-loop concern no longer applies because src/bls/bls.cpp is untouched in this PR's range, and useStlAlgorithm was suppressed wholesale from the very first linter commit rather than being enabled then rolled back, matching the PR description's disclosed burn-down trade-off. No new in-scope defects were found.
Source: reviewer backend models: gpt-5.6-sol (general) and gpt-5.6-sol (dash-core-commit-history); final verifier backend model: claude-sonnet-5. Orchestration-only, not reviewer evidence: openclaw-agent/cliproxy/gpt-5.6-sol.

Review provenance

  • Codex reviewers: gpt-5.6-sol — general (completed), gpt-5.6-sol — dash-core-commit-history (completed)
  • Verifier: claude-sonnet-5 — final-verifier
  • Sonnet reviewers: claude-sonnet-5 — dash-core-commit-history (completed), claude-sonnet-5 — general (completed)

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