From f2a419653cecc19e1c1a0cae6bb9016725e0f2a1 Mon Sep 17 00:00:00 2001 From: Paul Fultz II Date: Sun, 6 Feb 2022 13:15:45 -0600 Subject: [PATCH] Refactor ProgramMemory to store the expression tokens instead of exprIds (#3798) --- lib/programmemory.cpp | 141 +++++++++++++++++++++++------------------- lib/programmemory.h | 72 ++++++++++++++++++--- lib/valueflow.cpp | 69 ++++++++++++++------- 3 files changed, 185 insertions(+), 97 deletions(-) diff --git a/lib/programmemory.cpp b/lib/programmemory.cpp index 3ea3fdb3b..34c2e215e 100644 --- a/lib/programmemory.cpp +++ b/lib/programmemory.cpp @@ -38,14 +38,22 @@ #include #include -void ProgramMemory::setValue(nonneg int exprid, const ValueFlow::Value& value) +nonneg int ExprIdToken::getExpressionId() const { + return tok ? tok->exprId() : exprid; +} + +std::size_t ExprIdToken::Hash::operator()(ExprIdToken etok) const { - values[exprid] = value; + return std::hash()(etok.getExpressionId()); +} + +void ProgramMemory::setValue(const Token* expr, const ValueFlow::Value& value) { + mValues[expr] = value; } const ValueFlow::Value* ProgramMemory::getValue(nonneg int exprid, bool impossible) const { - const ProgramMemory::Map::const_iterator it = values.find(exprid); - const bool found = it != values.end() && (impossible || !it->second.isImpossible()); + const ProgramMemory::Map::const_iterator it = mValues.find(exprid); + const bool found = it != mValues.end() && (impossible || !it->second.isImpossible()); if (found) return &it->second; else @@ -63,12 +71,12 @@ bool ProgramMemory::getIntValue(nonneg int exprid, MathLib::bigint* result) cons return false; } -void ProgramMemory::setIntValue(nonneg int exprid, MathLib::bigint value, bool impossible) +void ProgramMemory::setIntValue(const Token* expr, MathLib::bigint value, bool impossible) { ValueFlow::Value v(value); if (impossible) v.setImpossible(); - values[exprid] = v; + mValues[expr] = v; } bool ProgramMemory::getTokValue(nonneg int exprid, const Token** result) const @@ -107,51 +115,67 @@ bool ProgramMemory::getContainerEmptyValue(nonneg int exprid, MathLib::bigint* r return false; } -void ProgramMemory::setContainerSizeValue(nonneg int exprid, MathLib::bigint value, bool isEqual) +void ProgramMemory::setContainerSizeValue(const Token* expr, MathLib::bigint value, bool isEqual) { ValueFlow::Value v(value); v.valueType = ValueFlow::Value::ValueType::CONTAINER_SIZE; if (!isEqual) v.valueKind = ValueFlow::Value::ValueKind::Impossible; - values[exprid] = v; + mValues[expr] = v; } -void ProgramMemory::setUnknown(nonneg int exprid) -{ - values[exprid].valueType = ValueFlow::Value::ValueType::UNINIT; +void ProgramMemory::setUnknown(const Token* expr) { + mValues[expr].valueType = ValueFlow::Value::ValueType::UNINIT; } bool ProgramMemory::hasValue(nonneg int exprid) { - return values.find(exprid) != values.end(); + return mValues.find(exprid) != mValues.end(); +} + +const ValueFlow::Value& ProgramMemory::at(nonneg int exprid) const { + return mValues.at(exprid); +} +ValueFlow::Value& ProgramMemory::at(nonneg int exprid) { + return mValues.at(exprid); +} + +void ProgramMemory::erase_if(const std::function& pred) +{ + for (auto it = mValues.begin(); it != mValues.end();) { + if (pred(it->first)) + it = mValues.erase(it); + else + ++it; + } } void ProgramMemory::swap(ProgramMemory &pm) { - values.swap(pm.values); + mValues.swap(pm.mValues); } void ProgramMemory::clear() { - values.clear(); + mValues.clear(); } bool ProgramMemory::empty() const { - return values.empty(); + return mValues.empty(); } void ProgramMemory::replace(const ProgramMemory &pm) { - for (auto&& p : pm.values) { - values[p.first] = p.second; + for (auto&& p : pm.mValues) { + mValues[p.first] = p.second; } } void ProgramMemory::insert(const ProgramMemory &pm) { - for (auto&& p:pm.values) - values.insert(p); + for (auto&& p : pm) + mValues.insert(p); } bool evaluateCondition(const std::string& op, @@ -216,10 +240,10 @@ void programMemoryParseCondition(ProgramMemory& pm, const Token* tok, const Toke if (endTok && isExpressionChanged(vartok, tok->next(), endTok, settings, true)) return; bool impossible = (tok->str() == "==" && !then) || (tok->str() == "!=" && then); - pm.setIntValue(vartok->exprId(), then ? truevalue.intvalue : falsevalue.intvalue, impossible); + pm.setIntValue(vartok, then ? truevalue.intvalue : falsevalue.intvalue, impossible); const Token* containerTok = settings->library.getContainerFromYield(vartok, Library::Container::Yield::SIZE); if (containerTok) - pm.setContainerSizeValue(containerTok->exprId(), then ? truevalue.intvalue : falsevalue.intvalue, !impossible); + pm.setContainerSizeValue(containerTok, then ? truevalue.intvalue : falsevalue.intvalue, !impossible); } else if (Token::simpleMatch(tok, "!")) { programMemoryParseCondition(pm, tok->astOperand1(), endTok, settings, !then); } else if (then && Token::simpleMatch(tok, "&&")) { @@ -240,10 +264,10 @@ void programMemoryParseCondition(ProgramMemory& pm, const Token* tok, const Toke } else if (tok->exprId() > 0) { if (endTok && isExpressionChanged(tok, tok->next(), endTok, settings, true)) return; - pm.setIntValue(tok->exprId(), 0, then); + pm.setIntValue(tok, 0, then); const Token* containerTok = settings->library.getContainerFromYield(tok, Library::Container::Yield::EMPTY); if (containerTok) - pm.setContainerSizeValue(containerTok->exprId(), 0, then); + pm.setContainerSizeValue(containerTok, 0, then); } } @@ -286,7 +310,7 @@ static void fillProgramMemoryFromAssignments(ProgramMemory& pm, const Token* tok continue; if (vartok == tok) continue; - pm.setValue(vartok->exprId(), p.second); + pm.setValue(vartok, p.second); setvar = true; } if (!setvar) { @@ -295,14 +319,14 @@ static void fillProgramMemoryFromAssignments(ProgramMemory& pm, const Token* tok bool error = false; execute(valuetok, &pm, &result, &error); if (!error) - pm.setIntValue(vartok->exprId(), result); + pm.setIntValue(vartok, result); else - pm.setUnknown(vartok->exprId()); + pm.setUnknown(vartok); } } } else if (tok2->exprId() > 0 && Token::Match(tok2, ".|(|[|*|%var%") && !pm.hasValue(tok2->exprId()) && isVariableChanged(tok2, 0, nullptr, true)) { - pm.setUnknown(tok2->exprId()); + pm.setUnknown(tok2); } if (tok2->str() == "{") { @@ -339,13 +363,9 @@ static void fillProgramMemoryFromAssignments(ProgramMemory& pm, const Token* tok static void removeModifiedVars(ProgramMemory& pm, const Token* tok, const Token* origin) { - for (auto i = pm.values.begin(), last = pm.values.end(); i != last;) { - if (isVariableChanged(origin, tok, i->first, false, nullptr, true)) { - i = pm.values.erase(i); - } else { - ++i; - } - } + pm.erase_if([&](const ExprIdToken& e) { + return isVariableChanged(origin, tok, e.getExpressionId(), false, nullptr, true); + }); } static ProgramMemory getInitialProgramState(const Token* tok, @@ -367,27 +387,24 @@ ProgramMemoryState::ProgramMemoryState(const Settings* s) : state(), origins(), void ProgramMemoryState::insert(const ProgramMemory &pm, const Token* origin) { if (origin) - for (auto&& p:pm.values) - origins.insert(std::make_pair(p.first, origin)); + for (auto&& p : pm) + origins.insert(std::make_pair(p.first.getExpressionId(), origin)); state.insert(pm); } void ProgramMemoryState::replace(const ProgramMemory &pm, const Token* origin) { if (origin) - for (auto&& p:pm.values) - origins[p.first] = origin; + for (auto&& p : pm) + origins[p.first.getExpressionId()] = origin; state.replace(pm); } static void addVars(ProgramMemory& pm, const ProgramMemory::Map& vars) { for (const auto& p:vars) { - nonneg int exprid = p.first; const ValueFlow::Value &value = p.second; - pm.setValue(exprid, value); - if (value.varId) - pm.setIntValue(value.varId, value.varvalue); + pm.setValue(p.first.tok, value); } } @@ -406,7 +423,7 @@ void ProgramMemoryState::assume(const Token* tok, bool b, bool isEmpty) { ProgramMemory pm = state; if (isEmpty) - pm.setContainerSizeValue(tok->exprId(), 0, b); + pm.setContainerSizeValue(tok, 0, b); else programMemoryParseCondition(pm, tok, nullptr, settings, b); const Token* origin = tok; @@ -418,16 +435,15 @@ void ProgramMemoryState::assume(const Token* tok, bool b, bool isEmpty) void ProgramMemoryState::removeModifiedVars(const Token* tok) { - for (auto i = state.values.begin(), last = state.values.end(); i != last;) { - const Token* start = origins[i->first]; - const Token* expr = findExpression(start ? start : tok, i->first); + state.erase_if([&](const ExprIdToken& e) { + const Token* start = origins[e.getExpressionId()]; + const Token* expr = e.tok; if (!expr || isExpressionChanged(expr, start, tok, settings, true)) { - origins.erase(i->first); - i = state.values.erase(i); - } else { - ++i; + origins.erase(e.getExpressionId()); + return true; } - } + return false; + }); } ProgramMemory ProgramMemoryState::get(const Token* tok, const Token* ctx, const ProgramMemory::Map& vars) const @@ -459,28 +475,23 @@ ProgramMemory getProgramMemory(const Token *tok, const ProgramMemory::Map& vars) fillProgramMemoryFromConditions(programMemory, tok, nullptr); ProgramMemory state; for (const auto& p:vars) { - nonneg int exprid = p.first; const ValueFlow::Value &value = p.second; - programMemory.setValue(exprid, value); - if (value.varId) - programMemory.setIntValue(value.varId, value.varvalue); + programMemory.setValue(p.first.tok, value); } state = programMemory; fillProgramMemoryFromAssignments(programMemory, tok, state, vars); return programMemory; } -ProgramMemory getProgramMemory(const Token* tok, nonneg int exprid, const ValueFlow::Value& value, const Settings *settings) +ProgramMemory getProgramMemory(const Token* tok, const Token* expr, const ValueFlow::Value& value, const Settings* settings) { ProgramMemory programMemory; programMemory.replace(getInitialProgramState(tok, value.tokvalue)); programMemory.replace(getInitialProgramState(tok, value.condition)); fillProgramMemoryFromConditions(programMemory, tok, settings); - programMemory.setValue(exprid, value); - if (value.varId) - programMemory.setIntValue(value.varId, value.varvalue); + programMemory.setValue(expr, value); const ProgramMemory state = programMemory; - fillProgramMemoryFromAssignments(programMemory, tok, state, {{exprid, value}}); + fillProgramMemoryFromAssignments(programMemory, tok, state, {{expr, value}}); return programMemory; } @@ -590,7 +601,7 @@ static ValueFlow::Value execute(const Token* expr, ProgramMemory& pm, const Sett if (expr->str() != "=") { if (!pm.hasValue(expr->astOperand1()->exprId())) return unknown; - ValueFlow::Value& lhs = pm.values.at(expr->astOperand1()->exprId()); + ValueFlow::Value& lhs = pm.at(expr->astOperand1()->exprId()); rhs = evaluate(removeAssign(expr->str()), lhs, rhs); if (lhs.isIntValue()) ValueFlow::Value::visitValue(rhs, std::bind(assign{}, std::ref(lhs.intvalue), std::placeholders::_1)); @@ -600,7 +611,7 @@ static ValueFlow::Value execute(const Token* expr, ProgramMemory& pm, const Sett return unknown; return lhs; } else { - pm.values[expr->astOperand1()->exprId()] = rhs; + pm.setValue(expr->astOperand1(), rhs); return rhs; } } else if (expr->str() == "&&" && expr->astOperand1() && expr->astOperand2()) { @@ -623,7 +634,7 @@ static ValueFlow::Value execute(const Token* expr, ProgramMemory& pm, const Sett } else if (Token::Match(expr, "++|--") && expr->astOperand1() && expr->astOperand1()->exprId() != 0) { if (!pm.hasValue(expr->astOperand1()->exprId())) return unknown; - ValueFlow::Value& lhs = pm.values.at(expr->astOperand1()->exprId()); + ValueFlow::Value& lhs = pm.at(expr->astOperand1()->exprId()); if (!lhs.isIntValue()) return unknown; // overflow @@ -705,7 +716,7 @@ static ValueFlow::Value execute(const Token* expr, ProgramMemory& pm, const Sett return execute(expr->astOperand1(), pm); } if (expr->exprId() > 0 && pm.hasValue(expr->exprId())) { - ValueFlow::Value result = pm.values.at(expr->exprId()); + ValueFlow::Value result = pm.at(expr->exprId()); if (result.isImpossible() && result.isIntValue() && result.intvalue == 0 && isUsedAsBool(expr)) { result.intvalue = !result.intvalue; result.setKnown(); @@ -716,7 +727,7 @@ static ValueFlow::Value execute(const Token* expr, ProgramMemory& pm, const Sett if (Token::Match(expr->previous(), ">|%name% {|(")) { visitAstNodes(expr->astOperand2(), [&](const Token* child) { if (child->exprId() > 0 && pm.hasValue(child->exprId())) { - ValueFlow::Value& v = pm.values.at(child->exprId()); + ValueFlow::Value& v = pm.at(child->exprId()); if (v.valueType == ValueFlow::Value::ValueType::CONTAINER_SIZE) { if (isContainerSizeChanged(child, settings)) v = unknown; diff --git a/lib/programmemory.h b/lib/programmemory.h index 2c2f7bb7e..0c034d807 100644 --- a/lib/programmemory.h +++ b/lib/programmemory.h @@ -28,25 +28,62 @@ class Token; class Settings; -struct ProgramMemory { - using Map = std::unordered_map; - Map values; +// Class used to handle heterogeneous lookup in unordered_map(since we can't use C++20 yet) +struct ExprIdToken { + const Token* tok = nullptr; + nonneg int exprid = 0; - void setValue(nonneg int exprid, const ValueFlow::Value& value); + ExprIdToken() = default; + // cppcheck-suppress noExplicitConstructor + ExprIdToken(const Token* tok) : tok(tok) {} + // TODO: Make this constructor only available from ProgramMemory + // cppcheck-suppress noExplicitConstructor + ExprIdToken(nonneg int exprid) : exprid(exprid) {} + + nonneg int getExpressionId() const; + + bool operator==(const ExprIdToken& rhs) const { + return getExpressionId() == rhs.getExpressionId(); + } + + template + friend bool operator!=(const T& lhs, const U& rhs) + { + return !(lhs == rhs); + } + + struct Hash { + std::size_t operator()(ExprIdToken etok) const; + }; +}; + +struct ProgramMemory { + using Map = std::unordered_map; + + ProgramMemory() = default; + + explicit ProgramMemory(const Map& values) : mValues(values) {} + + void setValue(const Token* expr, const ValueFlow::Value& value); const ValueFlow::Value* getValue(nonneg int exprid, bool impossible = false) const; bool getIntValue(nonneg int exprid, MathLib::bigint* result) const; - void setIntValue(nonneg int exprid, MathLib::bigint value, bool impossible = false); + void setIntValue(const Token* expr, MathLib::bigint value, bool impossible = false); bool getContainerSizeValue(nonneg int exprid, MathLib::bigint* result) const; bool getContainerEmptyValue(nonneg int exprid, MathLib::bigint* result) const; - void setContainerSizeValue(nonneg int exprid, MathLib::bigint value, bool isEqual = true); + void setContainerSizeValue(const Token* expr, MathLib::bigint value, bool isEqual = true); - void setUnknown(nonneg int exprid); + void setUnknown(const Token* expr); bool getTokValue(nonneg int exprid, const Token** result) const; bool hasValue(nonneg int exprid); + const ValueFlow::Value& at(nonneg int exprid) const; + ValueFlow::Value& at(nonneg int exprid); + + void erase_if(const std::function& pred); + void swap(ProgramMemory &pm); void clear(); @@ -56,6 +93,25 @@ struct ProgramMemory { void replace(const ProgramMemory &pm); void insert(const ProgramMemory &pm); + + Map::iterator begin() { + return mValues.begin(); + } + + Map::iterator end() { + return mValues.end(); + } + + Map::const_iterator begin() const { + return mValues.begin(); + } + + Map::const_iterator end() const { + return mValues.end(); + } + +private: + Map mValues; }; void programMemoryParseCondition(ProgramMemory& pm, const Token* tok, const Token* endTok, const Settings* settings, bool then); @@ -102,7 +158,7 @@ bool conditionIsTrue(const Token* condition, ProgramMemory pm, const Settings* s /** * Get program memory by looking backwards from given token. */ -ProgramMemory getProgramMemory(const Token* tok, nonneg int exprid, const ValueFlow::Value& value, const Settings *settings); +ProgramMemory getProgramMemory(const Token* tok, const Token* expr, const ValueFlow::Value& value, const Settings* settings); ProgramMemory getProgramMemory(const Token *tok, const ProgramMemory::Map& vars); diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index 7c2d2ef10..3ed6d5535 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -1967,7 +1967,7 @@ struct ValueFlowAnalyzer : Analyzer { virtual bool isAlias(const Token* tok, bool& inconclusive) const = 0; - using ProgramState = std::unordered_map; + using ProgramState = ProgramMemory::Map; virtual ProgramState getProgramState() const = 0; @@ -2693,7 +2693,7 @@ struct ExpressionAnalyzer : SingleValueFlowAnalyzer { virtual ProgramState getProgramState() const OVERRIDE { ProgramState ps; - ps[expr->exprId()] = value; + ps[expr] = value; return ps; } @@ -5971,16 +5971,22 @@ static bool valueFlowForLoop2(const Token *tok, return true; } -static void valueFlowForLoopSimplify(Token * const bodyStart, const nonneg int varid, bool globalvar, const MathLib::bigint value, TokenList *tokenlist, ErrorLogger *errorLogger, const Settings *settings) +static void valueFlowForLoopSimplify(Token* const bodyStart, + const Token* expr, + bool globalvar, + const MathLib::bigint value, + TokenList* tokenlist, + ErrorLogger* errorLogger, + const Settings* settings) { const Token * const bodyEnd = bodyStart->link(); // Is variable modified inside for loop - if (isVariableChanged(bodyStart, bodyEnd, varid, globalvar, settings, tokenlist->isCPP())) + if (isVariableChanged(bodyStart, bodyEnd, expr->varId(), globalvar, settings, tokenlist->isCPP())) return; for (Token *tok2 = bodyStart->next(); tok2 != bodyEnd; tok2 = tok2->next()) { - if (tok2->varId() == varid) { + if (tok2->varId() == expr->varId()) { const Token * parent = tok2->astParent(); while (parent) { const Token * const p = parent; @@ -6005,7 +6011,7 @@ static void valueFlowForLoopSimplify(Token * const bodyStart, const nonneg int v } if (Token::Match(tok2, "%oror%|&&")) { - const ProgramMemory programMemory(getProgramMemory(tok2->astTop(), varid, ValueFlow::Value(value), settings)); + const ProgramMemory programMemory(getProgramMemory(tok2->astTop(), expr, ValueFlow::Value(value), settings)); if ((tok2->str() == "&&" && !conditionIsTrue(tok2->astOperand1(), programMemory)) || (tok2->str() == "||" && !conditionIsFalse(tok2->astOperand1(), programMemory))) { // Skip second expression.. @@ -6022,12 +6028,16 @@ static void valueFlowForLoopSimplify(Token * const bodyStart, const nonneg int v } } - if ((tok2->str() == "&&" && conditionIsFalse(tok2->astOperand1(), getProgramMemory(tok2->astTop(), varid, ValueFlow::Value(value), settings))) || - (tok2->str() == "||" && conditionIsTrue(tok2->astOperand1(), getProgramMemory(tok2->astTop(), varid, ValueFlow::Value(value), settings)))) + if ((tok2->str() == "&&" && + conditionIsFalse(tok2->astOperand1(), + getProgramMemory(tok2->astTop(), expr, ValueFlow::Value(value), settings))) || + (tok2->str() == "||" && + conditionIsTrue(tok2->astOperand1(), + getProgramMemory(tok2->astTop(), expr, ValueFlow::Value(value), settings)))) break; - else if (Token::simpleMatch(tok2, ") {") && Token::findmatch(tok2->link(), "%varid%", tok2, varid)) { - if (Token::findmatch(tok2, "continue|break|return", tok2->linkAt(1), varid)) { + else if (Token::simpleMatch(tok2, ") {") && Token::findmatch(tok2->link(), "%varid%", tok2, expr->varId())) { + if (Token::findmatch(tok2, "continue|break|return", tok2->linkAt(1), expr->varId())) { if (settings->debugwarnings) bailout(tokenlist, errorLogger, tok2, "For loop variable bailout on conditional continue|break|return"); break; @@ -6036,7 +6046,7 @@ static void valueFlowForLoopSimplify(Token * const bodyStart, const nonneg int v bailout(tokenlist, errorLogger, tok2, "For loop variable skipping conditional scope"); tok2 = tok2->next()->link(); if (Token::simpleMatch(tok2, "} else {")) { - if (Token::findmatch(tok2, "continue|break|return", tok2->linkAt(2), varid)) { + if (Token::findmatch(tok2, "continue|break|return", tok2->linkAt(2), expr->varId())) { if (settings->debugwarnings) bailout(tokenlist, errorLogger, tok2, "For loop variable bailout on conditional continue|break|return"); break; @@ -6132,20 +6142,23 @@ static void valueFlowForLoop(TokenList *tokenlist, SymbolDatabase* symboldatabas ProgramMemory mem1, mem2, memAfter; if (valueFlowForLoop2(tok, &mem1, &mem2, &memAfter)) { ProgramMemory::Map::const_iterator it; - for (it = mem1.values.begin(); it != mem1.values.end(); ++it) { + for (it = mem1.begin(); it != mem1.end(); ++it) { if (!it->second.isIntValue()) continue; - valueFlowForLoopSimplify(bodyStart, it->first, false, it->second.intvalue, tokenlist, errorLogger, settings); + valueFlowForLoopSimplify( + bodyStart, it->first.tok, false, it->second.intvalue, tokenlist, errorLogger, settings); } - for (it = mem2.values.begin(); it != mem2.values.end(); ++it) { + for (it = mem2.begin(); it != mem2.end(); ++it) { if (!it->second.isIntValue()) continue; - valueFlowForLoopSimplify(bodyStart, it->first, false, it->second.intvalue, tokenlist, errorLogger, settings); + valueFlowForLoopSimplify( + bodyStart, it->first.tok, false, it->second.intvalue, tokenlist, errorLogger, settings); } - for (it = memAfter.values.begin(); it != memAfter.values.end(); ++it) { + for (it = memAfter.begin(); it != memAfter.end(); ++it) { if (!it->second.isIntValue()) continue; - valueFlowForLoopSimplifyAfter(tok, it->first, it->second.intvalue, tokenlist, settings); + valueFlowForLoopSimplifyAfter( + tok, it->first.getExpressionId(), it->second.intvalue, tokenlist, settings); } } } @@ -6289,13 +6302,15 @@ struct MultiValueFlowAnalyzer : ValueFlowAnalyzer { virtual ProgramState getProgramState() const OVERRIDE { ProgramState ps; - for (const auto& p:values) - ps[p.first] = p.second; + for (const auto& p : values) { + const Variable* var = vars.at(p.first); + ps[var->nameToken()] = p.second; + } return ps; } virtual void forkScope(const Token* endBlock) OVERRIDE { - ProgramMemory pm = {getProgramState()}; + ProgramMemory pm{getProgramState()}; const Scope* scope = endBlock->scope(); const Token* condTok = getCondTokFromEnd(endBlock); if (scope && condTok) @@ -6306,8 +6321,8 @@ struct MultiValueFlowAnalyzer : ValueFlowAnalyzer { pm.replace(endMemory); } // ProgramMemory pm = pms.get(endBlock->link()->next(), getProgramState()); - for (const auto& p:pm.values) { - nonneg int varid = p.first; + for (const auto& p : pm) { + nonneg int varid = p.first.getExpressionId(); if (symboldatabase && !symboldatabase->isVarId(varid)) continue; ValueFlow::Value value = p.second; @@ -6544,11 +6559,13 @@ static void valueFlowLibraryFunction(Token *tok, const std::string &returnValue, return; // set varids + std::unordered_map lookupVarId; for (Token* tok2 = tokenList.front(); tok2; tok2 = tok2->next()) { if (tok2->str().compare(0, 3, "arg") != 0) continue; nonneg int id = std::atoi(tok2->str().c_str() + 3); tok2->varId(id); + lookupVarId[id] = tok2; } // Evaluate expression @@ -6557,7 +6574,11 @@ static void valueFlowLibraryFunction(Token *tok, const std::string &returnValue, ValueFlow::valueFlowConstantFoldAST(expr, settings); productParams(argValues, [&](const std::unordered_map& arg) { - ProgramMemory pm{arg}; + ProgramMemory pm{}; + for (const auto& p : arg) { + const Token* tok = lookupVarId[p.first]; + pm.setValue(tok, p.second); + } MathLib::bigint result = 0; bool error = false; execute(expr, &pm, &result, &error); @@ -6758,7 +6779,7 @@ static void valueFlowFunctionReturn(TokenList *tokenlist, ErrorLogger *errorLogg programMemory.clear(); break; } - programMemory.setIntValue(arg->declarationId(), parvalues[i]); + programMemory.setIntValue(arg->nameToken(), parvalues[i]); } if (programMemory.empty() && !parvalues.empty()) continue;