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:
parent
f32583e097
commit
78228599da
|
@ -2181,6 +2181,8 @@ bool Token::addValue(const ValueFlow::Value &value)
|
||||||
|
|
||||||
// Add value
|
// Add value
|
||||||
if (it == mImpl->mValues->end()) {
|
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);
|
ValueFlow::Value v(value);
|
||||||
if (v.varId == 0)
|
if (v.varId == 0)
|
||||||
v.varId = mImpl->mVarId;
|
v.varId = mImpl->mVarId;
|
||||||
|
|
|
@ -2252,10 +2252,18 @@ struct ValueFlowAnalyzer : Analyzer {
|
||||||
const ValueFlow::Value* currValue = getValue(tok);
|
const ValueFlow::Value* currValue = getValue(tok);
|
||||||
if (!currValue)
|
if (!currValue)
|
||||||
return false;
|
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();
|
const bool exact = !currValue->isIntValue() || currValue->isImpossible();
|
||||||
for (const ValueFlow::Value& v : tok->values()) {
|
for (const ValueFlow::Value& v : tok->values()) {
|
||||||
if (!v.isSymbolicValue())
|
if (!v.isSymbolicValue())
|
||||||
continue;
|
continue;
|
||||||
|
if (currValue->equalValue(v))
|
||||||
|
continue;
|
||||||
const bool toImpossible = v.isImpossible() && currValue->isKnown();
|
const bool toImpossible = v.isImpossible() && currValue->isKnown();
|
||||||
if (!v.isKnown() && !toImpossible)
|
if (!v.isKnown() && !toImpossible)
|
||||||
continue;
|
continue;
|
||||||
|
@ -5056,9 +5064,23 @@ static bool isVariableInit(const Token *tok)
|
||||||
!Token::simpleMatch(tok->astOperand2(), ",");
|
!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)
|
static void valueFlowAfterAssign(TokenList *tokenlist, SymbolDatabase* symboldatabase, ErrorLogger *errorLogger, const Settings *settings)
|
||||||
{
|
{
|
||||||
for (const Scope * scope : symboldatabase->functionScopes) {
|
for (const Scope * scope : symboldatabase->functionScopes) {
|
||||||
|
std::unordered_map<nonneg int, std::unordered_set<nonneg int>> backAssigns;
|
||||||
std::set<nonneg int> aliased;
|
std::set<nonneg int> aliased;
|
||||||
for (Token* tok = const_cast<Token*>(scope->bodyStart); tok != scope->bodyEnd; tok = tok->next()) {
|
for (Token* tok = const_cast<Token*>(scope->bodyStart); tok != scope->bodyEnd; tok = tok->next()) {
|
||||||
// Alias
|
// Alias
|
||||||
|
@ -5122,12 +5144,30 @@ static void valueFlowAfterAssign(TokenList *tokenlist, SymbolDatabase* symboldat
|
||||||
if (tok->astOperand1()->exprId() > 0) {
|
if (tok->astOperand1()->exprId() > 0) {
|
||||||
Token* start = nextAfterAstRightmostLeaf(tok);
|
Token* start = nextAfterAstRightmostLeaf(tok);
|
||||||
const Token* end = scope->bodyEnd;
|
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) {
|
for (ValueFlow::Value value : values) {
|
||||||
if (!value.isSymbolicValue())
|
if (!value.isSymbolicValue())
|
||||||
continue;
|
continue;
|
||||||
const Token* expr = value.tokvalue;
|
const Token* expr = value.tokvalue;
|
||||||
value.intvalue = -value.intvalue;
|
value.intvalue = -value.intvalue;
|
||||||
value.tokvalue = tok->astOperand1();
|
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,
|
value.errorPath.emplace_back(tok,
|
||||||
tok->astOperand1()->expressionString() + " is assigned '" +
|
tok->astOperand1()->expressionString() + " is assigned '" +
|
||||||
tok->astOperand2()->expressionString() + "' here.");
|
tok->astOperand2()->expressionString() + "' here.");
|
||||||
|
|
|
@ -6447,6 +6447,21 @@ private:
|
||||||
" }\n"
|
" }\n"
|
||||||
"}\n";
|
"}\n";
|
||||||
valueOfTok(code, "swap");
|
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
|
void valueFlowCrashConstructorInitialization() { // #9577
|
||||||
|
|
Loading…
Reference in New Issue