Fix 10437: FP knownConditionTrueFalse after pointer check (#3646)

This commit is contained in:
Paul Fultz II 2021-12-20 00:28:40 -06:00 committed by GitHub
parent a3560aaf5a
commit 73f24b43f9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 63 additions and 31 deletions

View File

@ -128,34 +128,32 @@ void ProgramMemory::insert(const ProgramMemory &pm)
values.insert(p); 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) if (!condition)
return false; return false;
if (condition->str() == "&&") { if (condition->str() == op) {
return conditionIsFalse(condition->astOperand1(), programMemory) || return evaluateCondition(op, r, condition->astOperand1(), pm, settings) ||
conditionIsFalse(condition->astOperand2(), programMemory); evaluateCondition(op, r, condition->astOperand2(), pm, settings);
} }
ProgramMemory progmem(programMemory);
MathLib::bigint result = 0; MathLib::bigint result = 0;
bool error = false; bool error = false;
execute(condition, &progmem, &result, &error); execute(condition, &pm, &result, &error, settings);
return !error && result == 0; 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 evaluateCondition("&&", 0, condition, pm, settings);
return false;
if (condition->str() == "||") {
return conditionIsTrue(condition->astOperand1(), programMemory) ||
conditionIsTrue(condition->astOperand2(), programMemory);
} }
ProgramMemory progmem(programMemory);
bool error = false; bool conditionIsTrue(const Token* condition, ProgramMemory pm, const Settings* settings)
MathLib::bigint result = 0; {
execute(condition, &progmem, &result, &error); return evaluateCondition("||", 1, condition, pm, settings);
return !error && result == 1;
} }
static bool frontIs(const std::vector<MathLib::bigint>& v, bool i) static bool frontIs(const std::vector<MathLib::bigint>& v, bool i)
@ -518,7 +516,7 @@ static ValueFlow::Value evaluate(const std::string& op, const ValueFlow::Value&
return result; 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(); ValueFlow::Value unknown = ValueFlow::Value::unknown();
const ValueFlow::Value* value = nullptr; const ValueFlow::Value* value = nullptr;
@ -683,12 +681,32 @@ static ValueFlow::Value execute(const Token* expr, ProgramMemory& pm)
return result; 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; 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 (!v.isIntValue() || v.isImpossible()) {
if (error) if (error)
*error = true; *error = true;

View File

@ -61,21 +61,25 @@ struct ProgramMemoryState {
ProgramMemory get(const Token* tok, const Token* ctx, const ProgramMemory::Map& vars) const; 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? * Is condition always false when variable has given value?
* \param condition top ast token in condition * \param condition top ast token in condition
* \param programMemory program memory * \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? * Is condition always true when variable has given value?
* \param condition top ast token in condition * \param condition top ast token in condition
* \param programMemory program memory * \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. * Get program memory by looking backwards from given token.

View File

@ -1939,8 +1939,6 @@ static bool bifurcate(const Token* tok, const std::set<nonneg int>& varids, cons
return false; return false;
} }
static bool isContainerSizeChanged(const Token* tok, const Settings* settings = nullptr, int depth = 20);
struct ValueFlowAnalyzer : Analyzer { struct ValueFlowAnalyzer : Analyzer {
const TokenList* tokenlist; const TokenList* tokenlist;
ProgramMemoryState pms; ProgramMemoryState pms;
@ -2387,14 +2385,14 @@ struct ValueFlowAnalyzer : Analyzer {
std::vector<MathLib::bigint> result; std::vector<MathLib::bigint> result;
ProgramMemory pm = pms.get(tok, ctx, getProgramState()); ProgramMemory pm = pms.get(tok, ctx, getProgramState());
if (Token::Match(tok, "&&|%oror%")) { if (Token::Match(tok, "&&|%oror%")) {
if (conditionIsTrue(tok, pm)) if (conditionIsTrue(tok, pm, getSettings()))
result.push_back(1); result.push_back(1);
if (conditionIsFalse(tok, pm)) if (conditionIsFalse(tok, pm, getSettings()))
result.push_back(0); result.push_back(0);
} else { } else {
MathLib::bigint out = 0; MathLib::bigint out = 0;
bool error = false; bool error = false;
execute(tok, &pm, &out, &error); execute(tok, &pm, &out, &error, getSettings());
if (!error) if (!error)
result.push_back(out); 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) if (!tok)
return false; return false;

View File

@ -456,6 +456,8 @@ namespace ValueFlow {
std::vector<ValueFlow::Value> isOutOfBounds(const Value& size, const Token* indexTok, bool possible = true); std::vector<ValueFlow::Value> isOutOfBounds(const Value& size, const Token* indexTok, bool possible = true);
} }
bool isContainerSizeChanged(const Token* tok, const Settings* settings = nullptr, int depth = 20);
struct LifetimeToken { struct LifetimeToken {
const Token* token; const Token* token;
bool addressOf; bool addressOf;

View File

@ -3828,6 +3828,16 @@ private:
" if (bar(a) && (a + b == 3)) {}\n" " if (bar(a) && (a + b == 3)) {}\n"
"}\n"); "}\n");
ASSERT_EQUALS("", errout.str()); 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() void alwaysTrueSymbolic()