Skip to content
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions lib/valueflow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5160,9 +5160,10 @@ static void valueFlowInferCondition(TokenList& tokenlist, const Settings& settin
setTokenValue(tok, std::move(value), settings);
}
}
} else if (Token::Match(tok->astParent(), "?|&&|!|%oror%") ||
} else if (Token::Match(tok->astParent(), "&&|!|%oror%") ||
Token::Match(tok->astParent()->previous(), "if|while (") ||
(astIsPointer(tok) && isUsedAsBool(tok, settings))) {
(astIsPointer(tok) && isUsedAsBool(tok, settings)) ||
(astIsLHS(tok) && Token::simpleMatch(tok->astParent(), "?"))) {
std::vector<ValueFlow::Value> result = infer(makeIntegralInferModel(), "!=", tok->values(), 0);
if (result.size() != 1)
continue;
Expand Down
16 changes: 0 additions & 16 deletions lib/vf_settokenvalue.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -426,22 +426,6 @@ namespace ValueFlow
setTokenValue(parent, std::move(value), settings);
}
} else if (!value.isImpossible()) {
// is condition only depending on 1 variable?
nonneg int varId = 0;
bool ret = false;
visitAstNodes(parent->astOperand1(),
[&](const Token *t) {
if (t->varId()) {
if (varId > 0 || value.varId != 0)
ret = true;
varId = t->varId();
} else if (t->str() == "(" && Token::Match(t->previous(), "%name%"))
ret = true; // function call
return ret ? ChildrenToVisit::done : ChildrenToVisit::op1_and_op2;
});
if (ret)
return;

value.conditional = true;
value.changeKnownToPossible();

Expand Down
2 changes: 1 addition & 1 deletion test/testsymboldatabase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3631,7 +3631,7 @@ class TestSymbolDatabase : public TestFixture {
ASSERT(fredScope != nullptr);

// The struct Fred has two functions, a constructor and a destructor
ASSERT_EQUALS(2U, fredScope->functionList.size());
ASSERT_EQUALS(2U, fredScope->functionList.size()); // cppcheck-suppress nullPointer // see ticket #9747

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.

This is an AI review. Take it with a grain of salt and feel free to reject it by resolving the comment.

I confirmed that this suppression is needed because of the PR. With selfcheck's options (--check-level=exhaustive --library=cppcheck-lib ...), the merge base gives no warning here, while this PR gives Possible null pointer dereference: fredScope. It is a false positive, since assert_() throws when the condition fails. The cause is that the removed "condition depends on only one variable" guard in setTokenValue() used to drop the nullptr from (it == db->scopeList.end()) ? nullptr : &*it, because the condition contains a function call. So user code with the same "ternary + throwing check" pattern will now also hit #9747.

To get a feel for how often that happens, I compared warnings for the merge base and the PR on lib/, cli/, test/cfg/, samples/, testsymboldatabase.cpp and testvalueflow.cpp (normal check level, style/warning/portability/performance, inconclusive). Both gave exactly the same 2407 warnings, so it doesn't look widespread. Some correlated-ternary probes such as d = (a > b) ? 0 : a - b; if (a > b) return 0; return 10 / d; also stayed silent. Just mentioning it so the trade-off is a conscious one.


// Get linenumbers where the bodies for the constructor and destructor are..
unsigned int constructor = 0;
Expand Down
20 changes: 20 additions & 0 deletions test/testvalueflow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4286,6 +4286,26 @@ class TestValueFlow : public TestFixture {
"}\n";
auto values = tokenValues(code, "s :", ValueFlow::Value::ValueType::FLOAT);
ASSERT_EQUALS(0, values.size());

code = "int a[5];\n" // 15034
"int g(int i) {\n"
" return a[i < 0 ? -i : i];\n"
"}\n"
"int f() {\n"
" return g(-5);\n"
"}\n";
values = tokenValues(code, "?");
ASSERT_EQUALS(2, values.size());
auto it = values.begin();
ASSERT_EQUALS_ENUM(ValueFlow::Value::ValueType::INT, it->valueType);
ASSERT_EQUALS(0, it->intvalue);
ASSERT_EQUALS_ENUM(ValueFlow::Value::Bound::Lower, it->bound);
ASSERT_EQUALS_ENUM(ValueFlow::Value::ValueKind::Possible, it->valueKind);
++it;
ASSERT_EQUALS_ENUM(ValueFlow::Value::ValueType::INT, it->valueType);
ASSERT_EQUALS(5, it->intvalue);
ASSERT_EQUALS_ENUM(ValueFlow::Value::Bound::Point, it->bound);
ASSERT_EQUALS_ENUM(ValueFlow::Value::ValueKind::Possible, it->valueKind);
}

void valueFlowForwardLambda() {
Expand Down
Loading