Fix 10800: Hang / memory exhaustion on numerical code (#3822)

* Fix 10800: Hang / memory exhaustion on numerical code

* Format

* Add another test

* Format
This commit is contained in:
Paul Fultz II 2022-02-10 23:52:28 -06:00 committed by GitHub
parent f32583e097
commit 78228599da
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 57 additions and 0 deletions

View File

@ -2181,6 +2181,8 @@ bool Token::addValue(const ValueFlow::Value &value)
// Add value
if (it == mImpl->mValues->end()) {
// If the errorPath has gotten this large then there must be something wrong
assert(value.errorPath.size() < 64);
ValueFlow::Value v(value);
if (v.varId == 0)
v.varId = mImpl->mVarId;

View File

@ -2252,10 +2252,18 @@ struct ValueFlowAnalyzer : Analyzer {
const ValueFlow::Value* currValue = getValue(tok);
if (!currValue)
return false;
// If the same symbolic value is already there then skip
if (currValue->isSymbolicValue() &&
std::any_of(tok->values().begin(), tok->values().end(), [&](const ValueFlow::Value& v) {
return v.isSymbolicValue() && currValue->equalValue(v);
}))
return false;
const bool exact = !currValue->isIntValue() || currValue->isImpossible();
for (const ValueFlow::Value& v : tok->values()) {
if (!v.isSymbolicValue())
continue;
if (currValue->equalValue(v))
continue;
const bool toImpossible = v.isImpossible() && currValue->isKnown();
if (!v.isKnown() && !toImpossible)
continue;
@ -5056,9 +5064,23 @@ static bool isVariableInit(const Token *tok)
!Token::simpleMatch(tok->astOperand2(), ",");
}
// Return true if two associative containers intersect
template<class C1, class C2>
static bool intersects(const C1& c1, const C2& c2)
{
if (c1.size() > c2.size())
return intersects(c2, c1);
for (auto&& x : c1) {
if (c2.find(x) != c2.end())
return true;
}
return false;
}
static void valueFlowAfterAssign(TokenList *tokenlist, SymbolDatabase* symboldatabase, ErrorLogger *errorLogger, const Settings *settings)
{
for (const Scope * scope : symboldatabase->functionScopes) {
std::unordered_map<nonneg int, std::unordered_set<nonneg int>> backAssigns;
std::set<nonneg int> aliased;
for (Token* tok = const_cast<Token*>(scope->bodyStart); tok != scope->bodyEnd; tok = tok->next()) {
// Alias
@ -5122,12 +5144,30 @@ static void valueFlowAfterAssign(TokenList *tokenlist, SymbolDatabase* symboldat
if (tok->astOperand1()->exprId() > 0) {
Token* start = nextAfterAstRightmostLeaf(tok);
const Token* end = scope->bodyEnd;
// Collect symbolic ids
std::unordered_set<nonneg int> ids;
for (const ValueFlow::Value& value : values) {
if (!value.isSymbolicValue())
continue;
if (!value.tokvalue)
continue;
if (value.tokvalue->exprId() == 0)
continue;
ids.insert(value.tokvalue->exprId());
}
for (ValueFlow::Value value : values) {
if (!value.isSymbolicValue())
continue;
const Token* expr = value.tokvalue;
value.intvalue = -value.intvalue;
value.tokvalue = tok->astOperand1();
// Skip if it intersects with an already assigned symbol
auto& s = backAssigns[value.tokvalue->exprId()];
if (intersects(s, ids))
continue;
s.insert(expr->exprId());
value.errorPath.emplace_back(tok,
tok->astOperand1()->expressionString() + " is assigned '" +
tok->astOperand2()->expressionString() + "' here.");

View File

@ -6447,6 +6447,21 @@ private:
" }\n"
"}\n";
valueOfTok(code, "swap");
code = "double a;\n"
"int b, c, d, e, f, g;\n"
"void h() { double i, j = i = g = f = e = d = c = b = a; }\n";
valueOfTok(code, "a");
code = "double a, c;\n"
"double *b;\n"
"void d() {\n"
" double e, f, g, h = g = f = e = c = a;\n"
" b[8] = a;\n"
" b[1] = a;\n"
" a;\n"
"}\n";
valueOfTok(code, "a");
}
void valueFlowCrashConstructorInitialization() { // #9577