Skip to content

fix(const-param): say when a callee's const parameter is the only evidence - #198

Merged
SizzleUnrlsd merged 2 commits into
mainfrom
167-const-param-message
Oct 10, 2026
Merged

SizzleUnrlsd merged 2 commits into
mainfrom
167-const-param-message

Conversation

@SizzleUnrlsd

@SizzleUnrlsd SizzleUnrlsd commented Oct 10, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #167

Problem

A parameter passed where a pointer or reference to const is expected counted as not written from the callee's declaration alone, within one file and across files (#157). The message then said "is never used to modify the pointed object", although the callee's body is not checked:

static int bump(const int *p) { *(int *)p += 1; return *p; }
int use(int *p) { return bump(p); }   // reported: "is never used to modify the pointed object"

Fix

The rule keeps reporting the same parameters, as the cross-TU design keeps the callee's interface contract (A1). It now tells the two kinds of evidence apart:

  • a new write state, NoWriteByContract, for a callee's const parameter in the same file or from another file;
  • the merge keeps the least certain state, so the dependency on a contract is kept as soon as one use depends on it;
  • in that case only, the message says what the rule establishes:
ConstParameterNotModified.Pointer: parameter 'p' in function 'use' is only read, or passed where a pointer to const is expected
   ↳ current type: int *p
   ↳ suggested type: const int *p
   ↳ the callee's body is not checked: it may still modify the pointed object through a cast

The reference, T *const and rvalue-reference variants follow the same rule. A diagnostic established by the function's own uses keeps its message.

Tests

  • New fixture test/pointer_reference-const_correctness/const-callee-contract.c: the cast case with its new message and a not contains: on the old one, plus a witness without a call that keeps the old message.
  • New check check_const_param_contract_message_across_files: the same case with the callee in another file.
  • The headline of two existing expectations, which rest on a callee's const parameter alone, now uses the new wording: caller_const (advanced-cases.c) and caller_ref (advanced-cases.cpp).
  • The caveat line ends the block: the headline fallback of run_test.py ignores Info diagnostics, so a line inserted mid-block would break those expectations beyond their headline.
  • RED on main: 4/4 failing. GREEN: all pass.
  • Mutants caught: a fact winning over a contract in the merge, and either contract source treated as a fact.
  • CI-like suite on macOS arm64: 2394/2394, unit tests included. Linux is covered by this PR's CI.

Before / after (main b0982b2 vs this branch, macOS arm64)

  • Fixtures, default and z3: 848 runs, 1285 = 1285 diagnostics. 8 runs differ, by message only, on the 4 expected files.
  • Self-analysis, 4 chunks: 71 = 71 diagnostics. 7 messages change to the contract wording, with the same rule, function and line: runCrossTUSummaryPass (2), DirectModuleLoadingExecutionStrategy::execute, and 4 instances in StackComputation.cpp.

Limits

  • Code scanning may close and reopen the alerts of these 7 results, since their message changes. Triage will follow once CI has run.

Code scanning

CI is green on fc4dc03: 13 checks pass, the release attach step is skipped.

  • 66 open alerts on the merge ref, the same numbers as on main: none new, none gone.
  • No github-advanced-security comment on this PR. No new coretrace-concurrency-analyzer alert.
  • The SARIF uploaded by this PR's self-analysis carries the contract wording for the 7 results listed above (alerts 126, 128, 147, 252, 253, 264, 265), as on macOS. The code-scanning alerts API still returns their previous message, so the alerts were matched in place rather than reopened.

Linux validation

Run on Linux x86_64 (WSL, Ubuntu 24.04, LLVM 20) with main b0982b2 and this branch:

  • CI-like suite: 2394/2394, unit tests included.
  • Fixtures, default and z3: 848 runs, 1291 = 1291 diagnostics. 8 runs differ, by message only, on the same 4 files as on macOS.
  • Self-analysis, 4 chunks: 71 = 71 diagnostics; the same 7 messages change to the contract wording, with the same rule, function and line, as on macOS.

…idence

A parameter only passed where a pointer to const is expected is reported
as "never used to modify the pointed object", yet the callee's body is
not checked and may cast the qualifier away (#167).

Add a fixture with such a callee, its expected message and a witness
whose own body is the evidence, a check of the same case across files,
and update the headline of the two existing expectations that rest on a
callee's const parameter alone.
…dence

A parameter passed where a pointer or reference to const is expected
counted as not written, from the callee's declaration alone, within one
file and across files (#157). The message then stated that the object is
never modified, although the callee's body is not checked and may cast
the qualifier away.

Track that case as its own write state, kept by the merge whenever one
use depends on it, and say only what the rule establishes: the parameter
is only read, or passed where a pointer to const is expected, and the
callee's body is not checked. The same parameters are reported, and a
diagnostic established by the function's own uses keeps its message.

Fixes #167
@SizzleUnrlsd SizzleUnrlsd added the bug Something isn't working label Oct 10, 2026
@SizzleUnrlsd SizzleUnrlsd self-assigned this Oct 10, 2026
@SizzleUnrlsd
SizzleUnrlsd merged commit d7a58d6 into main Oct 10, 2026
14 checks passed
@SizzleUnrlsd
SizzleUnrlsd deleted the 167-const-param-message branch October 10, 2026 23:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ConstParameterNotModified: the message says the pointee is never modified when a callee's const parameter is the only evidence

1 participant