Fix issue 9849: false positive: containerOutOfBounds (#2753)
This commit is contained in:
parent
2028591ecf
commit
ec89c57a90
|
@ -4158,6 +4158,17 @@ static void insertImpossible(std::list<ValueFlow::Value>& values, const std::lis
|
|||
std::transform(input.begin(), input.end(), std::back_inserter(values), &asImpossible);
|
||||
}
|
||||
|
||||
static void insertNegateKnown(std::list<ValueFlow::Value>& values, const std::list<ValueFlow::Value>& input)
|
||||
{
|
||||
for(ValueFlow::Value value:input) {
|
||||
if (!value.isIntValue() && !value.isContainerSizeValue())
|
||||
continue;
|
||||
value.intvalue = !value.intvalue;
|
||||
value.setKnown();
|
||||
values.push_back(value);
|
||||
}
|
||||
}
|
||||
|
||||
static std::vector<const Variable*> getExprVariables(const Token* expr,
|
||||
const TokenList* tokenlist,
|
||||
const SymbolDatabase* symboldatabase,
|
||||
|
@ -4177,8 +4188,9 @@ struct ValueFlowConditionHandler {
|
|||
const Token *vartok;
|
||||
std::list<ValueFlow::Value> true_values;
|
||||
std::list<ValueFlow::Value> false_values;
|
||||
bool inverted = false;
|
||||
|
||||
Condition() : vartok(nullptr), true_values(), false_values() {}
|
||||
Condition() : vartok(nullptr), true_values(), false_values(), inverted(false) {}
|
||||
};
|
||||
std::function<bool(Token* start, const Token* stop, const Token* exprTok, const std::list<ValueFlow::Value>& values, bool constValue)>
|
||||
forward;
|
||||
|
@ -4278,16 +4290,22 @@ struct ValueFlowConditionHandler {
|
|||
std::list<ValueFlow::Value> thenValues;
|
||||
std::list<ValueFlow::Value> elseValues;
|
||||
|
||||
if (!Token::Match(tok, "!=|=") && tok != cond.vartok) {
|
||||
if (!Token::Match(tok, "!=|=|(|.") && tok != cond.vartok) {
|
||||
thenValues.insert(thenValues.end(), cond.true_values.begin(), cond.true_values.end());
|
||||
if (isConditionKnown(tok, false))
|
||||
insertImpossible(elseValues, cond.false_values);
|
||||
}
|
||||
if (!Token::Match(tok, "==|!")) {
|
||||
elseValues.insert(elseValues.end(), cond.false_values.begin(), cond.false_values.end());
|
||||
if (isConditionKnown(tok, true))
|
||||
if (isConditionKnown(tok, true)) {
|
||||
insertImpossible(thenValues, cond.true_values);
|
||||
if (Token::Match(tok, "(|.|%var%") && astIsBool(tok))
|
||||
insertNegateKnown(thenValues, cond.true_values);
|
||||
}
|
||||
}
|
||||
|
||||
if (cond.inverted)
|
||||
std::swap(thenValues, elseValues);
|
||||
|
||||
// start token of conditional code
|
||||
Token* startTokens[] = {nullptr, nullptr};
|
||||
|
@ -6020,6 +6038,7 @@ static void valueFlowContainerAfterCondition(TokenList *tokenlist,
|
|||
cond.true_values.emplace_back(value);
|
||||
cond.false_values.emplace_back(std::move(value));
|
||||
cond.vartok = vartok;
|
||||
cond.inverted = true;
|
||||
return cond;
|
||||
}
|
||||
// String compare
|
||||
|
|
|
@ -2479,6 +2479,39 @@ private:
|
|||
ASSERT_EQUALS(false, testValueOfX(code, 4U, 123));
|
||||
ASSERT_EQUALS(false, testValueOfX(code, 4U, 124));
|
||||
ASSERT_EQUALS(false, testValueOfX(code, 4U, 125));
|
||||
|
||||
code = "struct A {\n"
|
||||
" bool g() const;\n"
|
||||
"};\n"
|
||||
"void f(A a) {\n"
|
||||
" if (a.g()) {\n"
|
||||
" bool x = a.g();\n"
|
||||
" bool a = x;\n"
|
||||
" }\n"
|
||||
"}\n";
|
||||
ASSERT_EQUALS(false, testValueOfXKnown(code, 7U, 0));
|
||||
|
||||
code = "struct A {\n"
|
||||
" bool g() const;\n"
|
||||
"};\n"
|
||||
"void f(A a) {\n"
|
||||
" if (a.g()) {\n"
|
||||
" bool x = !a.g();\n"
|
||||
" bool a = x;\n"
|
||||
" }\n"
|
||||
"}\n";
|
||||
ASSERT_EQUALS(true, testValueOfXKnown(code, 7U, 0));
|
||||
|
||||
code = "struct A {\n"
|
||||
" bool g() const;\n"
|
||||
"};\n"
|
||||
"void f(A a) {\n"
|
||||
" if (!a.g()) {\n"
|
||||
" bool x = a.g();\n"
|
||||
" bool a = x;\n"
|
||||
" }\n"
|
||||
"}\n";
|
||||
ASSERT_EQUALS(true, testValueOfXKnown(code, 7U, 0));
|
||||
}
|
||||
|
||||
void valueFlowAfterConditionSeveralNot() {
|
||||
|
@ -4111,6 +4144,28 @@ private:
|
|||
"}";
|
||||
ASSERT(tokenValues(code, "params [ 2 ]").empty());
|
||||
|
||||
// valueFlowAfterCondition
|
||||
code = "void f(const std::vector<std::string>& v) {\n"
|
||||
" if(v.empty()) {\n"
|
||||
" v.front();\n"
|
||||
" }\n"
|
||||
"}\n";
|
||||
ASSERT_EQUALS("", isKnownContainerSizeValue(tokenValues(code, "v . front"), 0));
|
||||
|
||||
code = "void f(const std::vector<std::string>& v) {\n"
|
||||
" if(!v.empty()) {\n"
|
||||
" v.front();\n"
|
||||
" }\n"
|
||||
"}\n";
|
||||
ASSERT_EQUALS("", isImpossibleContainerSizeValue(tokenValues(code, "v . front"), 0));
|
||||
|
||||
code = "void f(const std::vector<std::string>& v) {\n"
|
||||
" if(!v.empty() && v[0] != \"\") {\n"
|
||||
" v.front();\n"
|
||||
" }\n"
|
||||
"}\n";
|
||||
ASSERT_EQUALS("", isImpossibleContainerSizeValue(tokenValues(code, "v . front"), 0));
|
||||
|
||||
// valueFlowContainerForward
|
||||
code = "void f(const std::list<int> &ints) {\n"
|
||||
" if (ints.empty()) {}\n"
|
||||
|
|
Loading…
Reference in New Issue