diff --git a/lib/programmemory.cpp b/lib/programmemory.cpp index 0644e3b8d..1dd612fb0 100644 --- a/lib/programmemory.cpp +++ b/lib/programmemory.cpp @@ -128,34 +128,32 @@ void ProgramMemory::insert(const ProgramMemory &pm) values.insert(p); } -bool conditionIsFalse(const Token *condition, const ProgramMemory &programMemory) +bool evaluateCondition(const std::string& op, + MathLib::bigint r, + const Token* condition, + ProgramMemory& pm, + const Settings* settings) { if (!condition) return false; - if (condition->str() == "&&") { - return conditionIsFalse(condition->astOperand1(), programMemory) || - conditionIsFalse(condition->astOperand2(), programMemory); + if (condition->str() == op) { + return evaluateCondition(op, r, condition->astOperand1(), pm, settings) || + evaluateCondition(op, r, condition->astOperand2(), pm, settings); } - ProgramMemory progmem(programMemory); MathLib::bigint result = 0; bool error = false; - execute(condition, &progmem, &result, &error); - return !error && result == 0; + execute(condition, &pm, &result, &error, settings); + return !error && result == r; } -bool conditionIsTrue(const Token *condition, const ProgramMemory &programMemory) +bool conditionIsFalse(const Token* condition, ProgramMemory pm, const Settings* settings) { - if (!condition) - return false; - if (condition->str() == "||") { - return conditionIsTrue(condition->astOperand1(), programMemory) || - conditionIsTrue(condition->astOperand2(), programMemory); - } - ProgramMemory progmem(programMemory); - bool error = false; - MathLib::bigint result = 0; - execute(condition, &progmem, &result, &error); - return !error && result == 1; + return evaluateCondition("&&", 0, condition, pm, settings); +} + +bool conditionIsTrue(const Token* condition, ProgramMemory pm, const Settings* settings) +{ + return evaluateCondition("||", 1, condition, pm, settings); } static bool frontIs(const std::vector& v, bool i) @@ -518,7 +516,7 @@ static ValueFlow::Value evaluate(const std::string& op, const ValueFlow::Value& return result; } -static ValueFlow::Value execute(const Token* expr, ProgramMemory& pm) +static ValueFlow::Value execute(const Token* expr, ProgramMemory& pm, const Settings* settings = nullptr) { ValueFlow::Value unknown = ValueFlow::Value::unknown(); const ValueFlow::Value* value = nullptr; @@ -683,12 +681,32 @@ static ValueFlow::Value execute(const Token* expr, ProgramMemory& pm) return result; } + 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()); + if (v.valueType == ValueFlow::Value::ValueType::CONTAINER_SIZE) { + if (isContainerSizeChanged(child, settings)) + v = unknown; + } else if (v.valueType != ValueFlow::Value::ValueType::UNINIT) { + if (isVariableChanged(child, v.indirect, settings, true)) + v = unknown; + } + } + return ChildrenToVisit::op1_and_op2; + }); + } + return unknown; } -void execute(const Token* expr, ProgramMemory* const programMemory, MathLib::bigint* result, bool* error) +void execute(const Token* expr, + ProgramMemory* const programMemory, + MathLib::bigint* result, + bool* error, + const Settings* settings) { - ValueFlow::Value v = execute(expr, *programMemory); + ValueFlow::Value v = execute(expr, *programMemory, settings); if (!v.isIntValue() || v.isImpossible()) { if (error) *error = true; diff --git a/lib/programmemory.h b/lib/programmemory.h index 17a727e43..5dfe5b156 100644 --- a/lib/programmemory.h +++ b/lib/programmemory.h @@ -61,21 +61,25 @@ struct ProgramMemoryState { ProgramMemory get(const Token* tok, const Token* ctx, const ProgramMemory::Map& vars) const; }; -void execute(const Token* expr, ProgramMemory* const programMemory, MathLib::bigint* result, bool* error); +void execute(const Token* expr, + ProgramMemory* const programMemory, + MathLib::bigint* result, + bool* error, + const Settings* settings = nullptr); /** * Is condition always false when variable has given value? * \param condition top ast token in condition * \param programMemory program memory */ -bool conditionIsFalse(const Token *condition, const ProgramMemory &programMemory); +bool conditionIsFalse(const Token* condition, ProgramMemory pm, const Settings* settings = nullptr); /** * Is condition always true when variable has given value? * \param condition top ast token in condition * \param programMemory program memory */ -bool conditionIsTrue(const Token *condition, const ProgramMemory &programMemory); +bool conditionIsTrue(const Token* condition, ProgramMemory pm, const Settings* settings = nullptr); /** * Get program memory by looking backwards from given token. diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index 8198951e8..f0f5a2409 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -1939,8 +1939,6 @@ static bool bifurcate(const Token* tok, const std::set& varids, cons return false; } -static bool isContainerSizeChanged(const Token* tok, const Settings* settings = nullptr, int depth = 20); - struct ValueFlowAnalyzer : Analyzer { const TokenList* tokenlist; ProgramMemoryState pms; @@ -2387,14 +2385,14 @@ struct ValueFlowAnalyzer : Analyzer { std::vector result; ProgramMemory pm = pms.get(tok, ctx, getProgramState()); if (Token::Match(tok, "&&|%oror%")) { - if (conditionIsTrue(tok, pm)) + if (conditionIsTrue(tok, pm, getSettings())) result.push_back(1); - if (conditionIsFalse(tok, pm)) + if (conditionIsFalse(tok, pm, getSettings())) result.push_back(0); } else { MathLib::bigint out = 0; bool error = false; - execute(tok, &pm, &out, &error); + execute(tok, &pm, &out, &error, getSettings()); if (!error) result.push_back(out); } @@ -7012,7 +7010,7 @@ static void valueFlowContainerReverse(Token* tok, } } -static bool isContainerSizeChanged(const Token* tok, const Settings* settings, int depth) +bool isContainerSizeChanged(const Token* tok, const Settings* settings, int depth) { if (!tok) return false; diff --git a/lib/valueflow.h b/lib/valueflow.h index dd6ad0e9a..78b36b4bb 100644 --- a/lib/valueflow.h +++ b/lib/valueflow.h @@ -456,6 +456,8 @@ namespace ValueFlow { std::vector isOutOfBounds(const Value& size, const Token* indexTok, bool possible = true); } +bool isContainerSizeChanged(const Token* tok, const Settings* settings = nullptr, int depth = 20); + struct LifetimeToken { const Token* token; bool addressOf; diff --git a/test/testcondition.cpp b/test/testcondition.cpp index bffa3eaf0..e695a62f2 100644 --- a/test/testcondition.cpp +++ b/test/testcondition.cpp @@ -3828,6 +3828,16 @@ private: " if (bar(a) && (a + b == 3)) {}\n" "}\n"); ASSERT_EQUALS("", errout.str()); + + // #10437 + check("void f() {\n" + " Obj* PObj = nullptr;\n" + " bool b = false;\n" + " if (GetObj(PObj) && PObj != nullptr)\n" + " b = true;\n" + " if (b) {}\n" + "}\n"); + ASSERT_EQUALS("", errout.str()); } void alwaysTrueSymbolic()