Skip to content

Fix 15042: ValueFlow: conditionally reassigned value should not be known - #8899

Open
pfultz2 wants to merge 8 commits into
cppcheck-opensource:mainfrom
pfultz2:programmmemory-multi-values
Open

pfultz2 wants to merge 8 commits into
cppcheck-opensource:mainfrom
pfultz2:programmmemory-multi-values

Conversation

@pfultz2

@pfultz2 pfultz2 commented Sep 27, 2026

Copy link
Copy Markdown
Collaborator

This refactors ProgramMemory so it can store a list of values.

A condition such as x > 3 was recorded as the possible value 4 with a lower bound, and the executor then used it as if x were exactly 4. Nested conditions were decided wrongly, so branches were skipped and values leaked past or were lost before them. This what lead to the FP in 15042.

Now it can understand these constraints better. As new values are added, it is resolved similar to Token::addValue.

Comment thread lib/programmemory.cpp
// Shifts: calculate() rejects a negative or too large shift and a negative value
bool error = false;
result = calculate(op, edge, k, &error);
if (!rangeIsLhs || error || (op == "<<" && (result >> k) != edge))
Comment thread lib/programmemory.cpp
// Shifts: calculate() rejects a negative or too large shift and a negative value
bool error = false;
result = calculate(op, edge, k, &error);
if (!rangeIsLhs || error || (op == "<<" && (result >> k) != edge))
Comment thread lib/programmemory.cpp
// known value and does not depend on a tracked value
const Values* getStoredValues(const Token* expr) const
{
if (expr->exprId() == 0)
Comment thread lib/programmemory.cpp
const ValueFlow::Value& v = utils::as_const(*pm).at(expr->exprId());
if (v.isIntValue())
return v;
if (const ValueFlow::Value* v = pm->getValue(expr->exprId(), /*impossible*/ true)) {

Copilot AI 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.

Copilot review overview

🟡 Changes recommended

Range propagation is currently unsound for wrapping arithmetic, casts, and compound updates, with additional precision and performance issues.

Review effort: Balanced
Findings: 1 High severity · 3 Medium severity

Open (4)
What changed in this PR

Refactors value-flow program memory to retain multiple constraints, fixing incorrect branch decisions for bounded conditions such as x > 3.

Changes:

  • Stores and merges multiple value constraints per expression.
  • Propagates ranges through arithmetic, conditions, containers, and execution.
  • Adds regression and unit coverage for range-aware analysis.
File Description
lib/​programmemory.cpp Implements multi-value storage and range execution.
lib/​programmemory.h Defines the new list-based API.
lib/​valueflow.cpp Improves bound solving and loop handling.
lib/​vfvalue.h Adds range-edge helpers.
lib/​vf_common.h Adds shared saturation detection.
lib/​vf_analyzers.cpp Adapts analyzer state to value lists.
lib/​token.cpp Exposes contradiction removal.
lib/​token.h Declares contradiction-removal API.
test/​testprogrammemory.cpp Tests constraints and range execution.
test/​testvalueflow.cpp Tests range-based value flow.
test/​testnullpointer.cpp Tests null-pointer analysis with ranges.
test/​testcondition.cpp Covers issue 15042’s false positive.
Makefile Adds the new header dependency.
oss-fuzz/​Makefile Updates fuzz-build dependencies.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread lib/programmemory.cpp
Comment on lines +879 to +883
if (op == "+") {
result = edge + k;
} else if (op == "-") {
increasing = rangeIsLhs;
result = rangeIsLhs ? edge - k : k - edge;
Comment thread lib/programmemory.cpp
Comment on lines +186 to +187
values.push_back(value);
Token::removeContradictions(values);
Comment thread lib/programmemory.cpp
Comment on lines 1807 to +1811
const ValueFlow::Value* sizeValue = pm->getValue(value.tokvalue->exprId());
if (sizeValue && sizeValue->isContainerSizeValue())
return *sizeValue;
if (sizeValue && sizeValue->isContainerSizeValue()) {
sizes.push_back(*sizeValue);
break;
}
Comment thread lib/programmemory.cpp
Comment on lines +1905 to +1910
// Shift every value of the variable; bounds and impossible values move along
for (ValueFlow::Value& v : lhs) {
if (expr->str() == "++")
v.intvalue++;
else
v.intvalue--;
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