Fix 10437: FP knownConditionTrueFalse after pointer check (#3646)
This commit is contained in:
parent
a3560aaf5a
commit
73f24b43f9
|
@ -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);
|
||||
return evaluateCondition("&&", 0, condition, pm, settings);
|
||||
}
|
||||
ProgramMemory progmem(programMemory);
|
||||
bool error = false;
|
||||
MathLib::bigint result = 0;
|
||||
execute(condition, &progmem, &result, &error);
|
||||
return !error && result == 1;
|
||||
|
||||
bool conditionIsTrue(const Token* condition, ProgramMemory pm, const Settings* settings)
|
||||
{
|
||||
return evaluateCondition("||", 1, condition, pm, settings);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -1939,8 +1939,6 @@ static bool bifurcate(const Token* tok, const std::set<nonneg int>& 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<MathLib::bigint> 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;
|
||||
|
|
|
@ -456,6 +456,8 @@ namespace ValueFlow {
|
|||
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 {
|
||||
const Token* token;
|
||||
bool addressOf;
|
||||
|
|
|
@ -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()
|
||||
|
|
Loading…
Reference in New Issue