Visitar URL original
Fix #15145 FN knownArgumentHiddenVariableExpression in if scope by chrchr-github · Pull Request #8974 · cppcheck-opensource/cppcheck · GitHub
Skip to content

Fix #15145 FN knownArgumentHiddenVariableExpression in if scope - #8974

Open
chrchr-github wants to merge 3 commits into
cppcheck-opensource:mainfrom
chrchr-github:chr_15145
Open

chrchr-github wants to merge 3 commits into
cppcheck-opensource:mainfrom
chrchr-github:chr_15145

Conversation

@chrchr-github

Copy link
Copy Markdown
Collaborator

No description provided.

@dmcppcheck

Copy link
Copy Markdown

Test results for commit e04ce1d (tools/test-my-pr.py, main compared to this PR):

Test: http://ec2-16-170-140-253.eu-north-1.compute.amazonaws.com/pr-8974/
packages: 100
Differing warnings: 1 (+1 -0)
AI review: 1 improvement (http://ec2-16-170-140-253.eu-north-1.compute.amazonaws.com/pr-8974/2026-10-28_10-35-33-e04ce1dd92d1-review.txt)
Timing: -0.2% (http://ec2-16-170-140-253.eu-north-1.compute.amazonaws.com/pr-8974/2026-10-28_10-35-33-e04ce1dd92d1_timing.html)

Posted automatically by the cppcheck PR test runner. +N: warnings only with this PR, -N: warnings only with main. The AI review is written by Claude and can be wrong.

@dmcppcheck dmcppcheck 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.

AI review

The change brings in new knownArgument false positives with misleading messages. Before this PR, an x that had any ValueFlow values was skipped. Now an x whose first value is impossible is accepted, and impossible values are exactly what conditions and unsigned types produce. So comparisons whose result is decided by earlier code, not by a constant literal, are now reported with "It does not matter what value 'x' has":

  • if (x != 0) g(x == 0);
  • if (x < 0) return; g(x >= 0);

In both cases the value of x is what decides the result, so the message is wrong. The real problem in that code is a redundant or always-false condition.

For unsigned values (g(x >= 0), g(x < 0) with unsigned x), the new warning duplicates the existing unsignedPositive / unsignedLessThanZero warnings.

The case the PR targets, if (x != 0) g(0 * x);, works as intended. Variants such as if (x == 0) return; g(x * 0);, unsigned x * 0 and s.a * 0 are now reported too.

A suggestion, not tested: only accept impossible values for the hidden-literal case (an operand of *, &, && or || that is a known 0 or 1 literal), or exclude comparison operators.

Testing

I built cppcheck and testrunner in pr/ and cppcheck in base/. ./testrunner TestOther passes (0 failures).

Scratch tests

a.cpp: the new detections that are correct, all reported only by the PR:

  • if (x != 0) g(0 * x);
  • if (x == 0) return; g(x * 0);
  • void f(unsigned x){ g(x * 0); }
  • if (x != 0) g(x & 0);

For if (s.a != 1) g(s.a * 0);, the warning changes from knownArgument on a to knownArgumentHiddenVariableExpression on s.a.

b.cpp: the new false positives and duplicates.

void g(int);
void f2(unsigned x) { g(x >= 0); }
void f3(unsigned x) { g(x < 0); }
void f5(int x) { if (x != 0) g(x == 0); }
void f8(int x) { if (x < 0) return; g(x >= 0); }

Command: cppcheck -q --enable=style --template='{line}:{id}:{message}' b.cpp

base:

2:unsignedPositive:Unsigned expression 'x' can't be negative so it is unnecessary to test it.
3:unsignedLessThanZero:Checking if unsigned expression 'x' is less than zero.

pr has both of those lines and also:

2:knownArgument:Argument 'x>=0' to function g is always 1. It does not matter what value 'x' has.
3:knownArgument:Argument 'x<0' to function g is always 0. It does not matter what value 'x' has.
4:knownArgument:Argument 'x==0' to function g is always 0. It does not matter what value 'x' has.
5:knownArgument:Argument 'x>=0' to function g is always 1. It does not matter what value 'x' has.

(Line numbers in the outputs are for the 5-line file shown; in my scratch file these lines are 4, 5, 7 and 10.)


Automated review of e04ce1d by Claude. The pull request was built and tested locally.

Comment thread lib/checkother.cpp
return ChildrenToVisit::none;
if (astIsIntegral(child, false) && !astIsPointer(child) && child->values().empty()) {
if (astIsIntegral(child, false) && !astIsPointer(child) &&
(child->values().empty() || (child->values().front().isIntValue() && child->values().front().isImpossible()))) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

AI review

Accepting a variable whose first value is impossible also lets through comparisons whose result follows from those impossible values, and those warnings are wrong. With this PR:

  • void f(int x) { if (x != 0) g(x == 0); } gives Argument 'x==0' to function g is always 0. It does not matter what value 'x' has. [knownArgument]
  • if (x < 0) return; g(x >= 0); gives the same kind of warning.
  • void f(unsigned x) { g(x >= 0); } and g(x < 0) give the same kind of warning, on top of the existing unsignedPositive / unsignedLessThanZero.

The value of x is what decides each of these results, so "It does not matter what value 'x' has" is misleading. Base reports none of them. Consider accepting impossible values only when a constant literal (0*x, x&0, ...) hides the variable, or skipping comparison operators here, and add a negative test such as if (x != 0) g(x == 0);.

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.

2 participants