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);
|
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,
|
static std::vector<const Variable*> getExprVariables(const Token* expr,
|
||||||
const TokenList* tokenlist,
|
const TokenList* tokenlist,
|
||||||
const SymbolDatabase* symboldatabase,
|
const SymbolDatabase* symboldatabase,
|
||||||
|
@ -4177,8 +4188,9 @@ struct ValueFlowConditionHandler {
|
||||||
const Token *vartok;
|
const Token *vartok;
|
||||||
std::list<ValueFlow::Value> true_values;
|
std::list<ValueFlow::Value> true_values;
|
||||||
std::list<ValueFlow::Value> false_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)>
|
std::function<bool(Token* start, const Token* stop, const Token* exprTok, const std::list<ValueFlow::Value>& values, bool constValue)>
|
||||||
forward;
|
forward;
|
||||||
|
@ -4278,17 +4290,23 @@ struct ValueFlowConditionHandler {
|
||||||
std::list<ValueFlow::Value> thenValues;
|
std::list<ValueFlow::Value> thenValues;
|
||||||
std::list<ValueFlow::Value> elseValues;
|
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());
|
thenValues.insert(thenValues.end(), cond.true_values.begin(), cond.true_values.end());
|
||||||
if (isConditionKnown(tok, false))
|
if (isConditionKnown(tok, false))
|
||||||
insertImpossible(elseValues, cond.false_values);
|
insertImpossible(elseValues, cond.false_values);
|
||||||
}
|
}
|
||||||
if (!Token::Match(tok, "==|!")) {
|
if (!Token::Match(tok, "==|!")) {
|
||||||
elseValues.insert(elseValues.end(), cond.false_values.begin(), cond.false_values.end());
|
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);
|
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
|
// start token of conditional code
|
||||||
Token* startTokens[] = {nullptr, nullptr};
|
Token* startTokens[] = {nullptr, nullptr};
|
||||||
|
|
||||||
|
@ -6020,6 +6038,7 @@ static void valueFlowContainerAfterCondition(TokenList *tokenlist,
|
||||||
cond.true_values.emplace_back(value);
|
cond.true_values.emplace_back(value);
|
||||||
cond.false_values.emplace_back(std::move(value));
|
cond.false_values.emplace_back(std::move(value));
|
||||||
cond.vartok = vartok;
|
cond.vartok = vartok;
|
||||||
|
cond.inverted = true;
|
||||||
return cond;
|
return cond;
|
||||||
}
|
}
|
||||||
// String compare
|
// String compare
|
||||||
|
|
|
@ -2479,6 +2479,39 @@ private:
|
||||||
ASSERT_EQUALS(false, testValueOfX(code, 4U, 123));
|
ASSERT_EQUALS(false, testValueOfX(code, 4U, 123));
|
||||||
ASSERT_EQUALS(false, testValueOfX(code, 4U, 124));
|
ASSERT_EQUALS(false, testValueOfX(code, 4U, 124));
|
||||||
ASSERT_EQUALS(false, testValueOfX(code, 4U, 125));
|
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() {
|
void valueFlowAfterConditionSeveralNot() {
|
||||||
|
@ -4111,6 +4144,28 @@ private:
|
||||||
"}";
|
"}";
|
||||||
ASSERT(tokenValues(code, "params [ 2 ]").empty());
|
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
|
// valueFlowContainerForward
|
||||||
code = "void f(const std::list<int> &ints) {\n"
|
code = "void f(const std::list<int> &ints) {\n"
|
||||||
" if (ints.empty()) {}\n"
|
" if (ints.empty()) {}\n"
|
||||||
|
|
Loading…
Reference in New Issue