diff --git a/lib/programmemory.cpp b/lib/programmemory.cpp index 6b57b738b..7ec72eb16 100644 --- a/lib/programmemory.cpp +++ b/lib/programmemory.cpp @@ -50,6 +50,20 @@ std::size_t ExprIdToken::Hash::operator()(ExprIdToken etok) const void ProgramMemory::setValue(const Token* expr, const ValueFlow::Value& value) { mValues[expr] = value; + ValueFlow::Value subvalue = value; + const Token* subexpr = solveExprValue( + expr, + [&](const Token* tok) -> std::vector { + if (tok->hasKnownIntValue()) + return {tok->values().front().intvalue}; + MathLib::bigint result = 0; + if (getIntValue(tok->exprId(), &result)) + return {result}; + return {}; + }, + subvalue); + if (subexpr) + mValues[subexpr] = subvalue; } const ValueFlow::Value* ProgramMemory::getValue(nonneg int exprid, bool impossible) const { @@ -77,7 +91,7 @@ void ProgramMemory::setIntValue(const Token* expr, MathLib::bigint value, bool i ValueFlow::Value v(value); if (impossible) v.setImpossible(); - mValues[expr] = v; + setValue(expr, v); } bool ProgramMemory::getTokValue(nonneg int exprid, const Token** result) const @@ -122,7 +136,7 @@ void ProgramMemory::setContainerSizeValue(const Token* expr, MathLib::bigint val v.valueType = ValueFlow::Value::ValueType::CONTAINER_SIZE; if (!isEqual) v.valueKind = ValueFlow::Value::ValueKind::Impossible; - mValues[expr] = v; + setValue(expr, v); } void ProgramMemory::setUnknown(const Token* expr) { diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index 4ea28f2d3..70a7e8b44 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -2936,38 +2936,43 @@ static Analyzer::Result valueFlowForwardExpression(Token* startToken, return result; } -static const Token* parseBinaryIntOp(const Token* expr, MathLib::bigint& known) +static const Token* parseBinaryIntOp(const Token* expr, + const std::function(const Token*)>& eval, + MathLib::bigint& known) { if (!expr) return nullptr; if (!expr->astOperand1() || !expr->astOperand2()) return nullptr; - if (expr->astOperand1()->exprId() == 0 && !expr->astOperand1()->hasKnownIntValue()) + if (expr->astOperand1()->exprId() == 0 && expr->astOperand2()->exprId() == 0) return nullptr; - if (expr->astOperand2()->exprId() == 0 && !expr->astOperand2()->hasKnownIntValue()) + std::vector x1 = eval(expr->astOperand1()); + std::vector x2 = eval(expr->astOperand2()); + if (expr->astOperand1()->exprId() == 0 && x1.empty()) + return nullptr; + if (expr->astOperand2()->exprId() == 0 && x2.empty()) return nullptr; - const Token* knownTok = nullptr; const Token* varTok = nullptr; - if (expr->astOperand1()->hasKnownIntValue() && !expr->astOperand2()->hasKnownIntValue()) { + if (!x1.empty() && x2.empty()) { varTok = expr->astOperand2(); - knownTok = expr->astOperand1(); - } else if (expr->astOperand2()->hasKnownIntValue() && !expr->astOperand1()->hasKnownIntValue()) { + known = x1.front(); + } else if (x1.empty() && !x2.empty()) { varTok = expr->astOperand1(); - knownTok = expr->astOperand2(); + known = x2.front(); } - if (knownTok) - known = knownTok->values().front().intvalue; return varTok; } -static const Token* solveExprValue(const Token* expr, ValueFlow::Value& value) +const Token* solveExprValue(const Token* expr, + const std::function(const Token*)>& eval, + ValueFlow::Value& value) { if (!value.isIntValue() && !value.isIteratorValue() && !value.isSymbolicValue()) return expr; if (value.isSymbolicValue() && !Token::Match(expr, "+|-")) return expr; MathLib::bigint intval; - const Token* binaryTok = parseBinaryIntOp(expr, intval); + const Token* binaryTok = parseBinaryIntOp(expr, eval, intval); bool rhs = astIsRHS(binaryTok); // If its on the rhs, then -1 multiplication is needed, which is not possible with simple delta analysis used currently for symbolic values if (value.isSymbolicValue() && rhs && Token::simpleMatch(expr, "-")) @@ -2976,30 +2981,42 @@ static const Token* solveExprValue(const Token* expr, ValueFlow::Value& value) switch (expr->str()[0]) { case '+': { value.intvalue -= intval; - return solveExprValue(binaryTok, value); + return solveExprValue(binaryTok, eval, value); } case '-': { if (rhs) value.intvalue = intval - value.intvalue; else value.intvalue += intval; - return solveExprValue(binaryTok, value); + return solveExprValue(binaryTok, eval, value); } case '*': { if (intval == 0) break; value.intvalue /= intval; - return solveExprValue(binaryTok, value); + return solveExprValue(binaryTok, eval, value); } case '^': { value.intvalue ^= intval; - return solveExprValue(binaryTok, value); + return solveExprValue(binaryTok, eval, value); } } } return expr; } +static const Token* solveExprValue(const Token* expr, ValueFlow::Value& value) +{ + return solveExprValue( + expr, + [](const Token* tok) -> std::vector { + if (tok->hasKnownIntValue()) + return {tok->values().front().intvalue}; + return {}; + }, + value); +} + ValuePtr makeAnalyzer(const Token* exprTok, ValueFlow::Value value, const TokenList* tokenlist) { const Token* expr = solveExprValue(exprTok, value); diff --git a/lib/valueflow.h b/lib/valueflow.h index 6886d50c2..a89a6daf0 100644 --- a/lib/valueflow.h +++ b/lib/valueflow.h @@ -503,6 +503,10 @@ ValueFlow::Value inferCondition(const std::string& op, const Token* varTok, Math CPPCHECKLIB ValuePtr makeIntegralInferModel(); +const Token* solveExprValue(const Token* expr, + const std::function(const Token*)>& eval, + ValueFlow::Value& value); + std::vector getLifetimeTokens(const Token* tok, bool escape = false, ValueFlow::Value::ErrorPath errorPath = ValueFlow::Value::ErrorPath{}); diff --git a/test/testuninitvar.cpp b/test/testuninitvar.cpp index ec2f23bf3..6e6c91d9b 100644 --- a/test/testuninitvar.cpp +++ b/test/testuninitvar.cpp @@ -3612,6 +3612,17 @@ private: " int a[ 2 ] = { [ 0 ] = *p++, [ 1 ] = 1 };\n" "}"); ASSERT_EQUALS("[test.cpp:3]: (error) Uninitialized variable: p\n", errout.str()); + + valueFlowUninit("void f(int height) {\n" + " int a[11];\n" + " int *p = a;\n" + " int step = 2;\n" + " for (int i = 0; i < (height * step); i += step)\n" + " *p++ = 0;\n" + " for (int i = 0; i < height; i++)\n" + " if (a[i]) {}\n" + "}\n"); + ASSERT_EQUALS("", errout.str()); } void uninitStructMember() { // struct members