Repository navigation
Fix #15145 FN knownArgumentHiddenVariableExpression in if scope - #8974
chrchr-github wants to merge 3 commits into
Conversation
|
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/ 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
left a comment
There was a problem hiding this comment.
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.
| 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()))) { |
There was a problem hiding this comment.
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); }givesArgument '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); }andg(x < 0)give the same kind of warning, on top of the existingunsignedPositive/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);.
No description provided.