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);
|
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;
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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()
|
||||||
|
|
Loading…
Reference in New Issue