Fix issue 11867: Assert failure in valueFlowContainerSize() (#5317)
This commit is contained in:
parent
466da1e77a
commit
48c91abba6
|
@ -259,6 +259,18 @@ bool astIsContainerOwned(const Token* tok) {
|
||||||
return astIsContainer(tok) && !astIsContainerView(tok);
|
return astIsContainer(tok) && !astIsContainerView(tok);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool astIsContainerString(const Token* tok)
|
||||||
|
{
|
||||||
|
if (!tok)
|
||||||
|
return false;
|
||||||
|
if (!tok->valueType())
|
||||||
|
return false;
|
||||||
|
const Library::Container* container = tok->valueType()->container;
|
||||||
|
if (!container)
|
||||||
|
return false;
|
||||||
|
return container->stdStringLike;
|
||||||
|
}
|
||||||
|
|
||||||
static const Token* getContainerFunction(const Token* tok)
|
static const Token* getContainerFunction(const Token* tok)
|
||||||
{
|
{
|
||||||
if (!tok || !tok->valueType() || !tok->valueType()->container)
|
if (!tok || !tok->valueType() || !tok->valueType()->container)
|
||||||
|
|
|
@ -149,6 +149,7 @@ bool astIsContainer(const Token *tok);
|
||||||
|
|
||||||
bool astIsContainerView(const Token* tok);
|
bool astIsContainerView(const Token* tok);
|
||||||
bool astIsContainerOwned(const Token* tok);
|
bool astIsContainerOwned(const Token* tok);
|
||||||
|
bool astIsContainerString(const Token* tok);
|
||||||
|
|
||||||
Library::Container::Action astContainerAction(const Token* tok, const Token** ftok = nullptr);
|
Library::Container::Action astContainerAction(const Token* tok, const Token** ftok = nullptr);
|
||||||
Library::Container::Yield astContainerYield(const Token* tok, const Token** ftok = nullptr);
|
Library::Container::Yield astContainerYield(const Token* tok, const Token** ftok = nullptr);
|
||||||
|
|
|
@ -696,7 +696,11 @@ static void setTokenValue(Token* tok,
|
||||||
if (value.isImpossible()) {
|
if (value.isImpossible()) {
|
||||||
if (value.intvalue == 0)
|
if (value.intvalue == 0)
|
||||||
v.setKnown();
|
v.setKnown();
|
||||||
else
|
else if ((value.bound == ValueFlow::Value::Bound::Upper && value.intvalue > 0) ||
|
||||||
|
(value.bound == ValueFlow::Value::Bound::Lower && value.intvalue < 0)) {
|
||||||
|
v.intvalue = 0;
|
||||||
|
v.setKnown();
|
||||||
|
} else
|
||||||
v.setPossible();
|
v.setPossible();
|
||||||
} else {
|
} else {
|
||||||
v.intvalue = !v.intvalue;
|
v.intvalue = !v.intvalue;
|
||||||
|
@ -8660,6 +8664,9 @@ static void valueFlowContainerSetTokValue(TokenList& tokenlist, const Settings*
|
||||||
ValueFlow::Value value;
|
ValueFlow::Value value;
|
||||||
value.valueType = ValueFlow::Value::ValueType::TOK;
|
value.valueType = ValueFlow::Value::ValueType::TOK;
|
||||||
value.tokvalue = initList;
|
value.tokvalue = initList;
|
||||||
|
if (astIsContainerString(tok) && Token::simpleMatch(initList, "{") && Token::Match(initList->astOperand2(), "%str%")) {
|
||||||
|
value.tokvalue = initList->astOperand2();
|
||||||
|
}
|
||||||
value.setKnown();
|
value.setKnown();
|
||||||
Token* start = initList->link() ? initList->link() : initList->next();
|
Token* start = initList->link() ? initList->link() : initList->next();
|
||||||
if (tok->variable() && tok->variable()->isConst()) {
|
if (tok->variable() && tok->variable()->isConst()) {
|
||||||
|
@ -8675,6 +8682,19 @@ static const Scope* getFunctionScope(const Scope* scope) {
|
||||||
return scope;
|
return scope;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static MathLib::bigint valueFlowGetStrLength(const Token* tok)
|
||||||
|
{
|
||||||
|
if (tok->tokType() == Token::eString)
|
||||||
|
return Token::getStrLength(tok);
|
||||||
|
if (astIsGenericChar(tok) || tok->tokType() == Token::eChar)
|
||||||
|
return 1;
|
||||||
|
if (const ValueFlow::Value* v2 = tok->getKnownValue(ValueFlow::Value::ValueType::CONTAINER_SIZE))
|
||||||
|
return v2->intvalue;
|
||||||
|
if (const ValueFlow::Value* v1 = tok->getKnownValue(ValueFlow::Value::ValueType::TOK))
|
||||||
|
return valueFlowGetStrLength(v1->tokvalue);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static void valueFlowContainerSize(TokenList& tokenlist,
|
static void valueFlowContainerSize(TokenList& tokenlist,
|
||||||
const SymbolDatabase& symboldatabase,
|
const SymbolDatabase& symboldatabase,
|
||||||
ErrorLogger* /*errorLogger*/,
|
ErrorLogger* /*errorLogger*/,
|
||||||
|
@ -8819,21 +8839,12 @@ static void valueFlowContainerSize(TokenList& tokenlist,
|
||||||
} else if (Token::simpleMatch(tok, "+=") && astIsContainer(tok->astOperand1())) {
|
} else if (Token::simpleMatch(tok, "+=") && astIsContainer(tok->astOperand1())) {
|
||||||
const Token* containerTok = tok->astOperand1();
|
const Token* containerTok = tok->astOperand1();
|
||||||
const Token* valueTok = tok->astOperand2();
|
const Token* valueTok = tok->astOperand2();
|
||||||
MathLib::bigint size = 0;
|
MathLib::bigint size = valueFlowGetStrLength(valueTok);
|
||||||
if (valueTok->tokType() == Token::eString)
|
|
||||||
size = Token::getStrLength(valueTok);
|
|
||||||
else if (astIsGenericChar(tok) || valueTok->tokType() == Token::eChar)
|
|
||||||
size = 1;
|
|
||||||
else if (const ValueFlow::Value* v1 = valueTok->getKnownValue(ValueFlow::Value::ValueType::TOK))
|
|
||||||
size = Token::getStrLength(v1->tokvalue);
|
|
||||||
else if (const ValueFlow::Value* v2 =
|
|
||||||
valueTok->getKnownValue(ValueFlow::Value::ValueType::CONTAINER_SIZE))
|
|
||||||
size = v2->intvalue;
|
|
||||||
if (size == 0)
|
if (size == 0)
|
||||||
continue;
|
continue;
|
||||||
ValueFlow::Value value(size - 1);
|
ValueFlow::Value value(size - 1);
|
||||||
value.valueType = ValueFlow::Value::ValueType::CONTAINER_SIZE;
|
value.valueType = ValueFlow::Value::ValueType::CONTAINER_SIZE;
|
||||||
value.bound = ValueFlow::Value::Bound::Lower;
|
value.bound = ValueFlow::Value::Bound::Upper;
|
||||||
value.setImpossible();
|
value.setImpossible();
|
||||||
Token* next = nextAfterAstRightmostLeaf(tok);
|
Token* next = nextAfterAstRightmostLeaf(tok);
|
||||||
if (!next)
|
if (!next)
|
||||||
|
|
|
@ -5028,6 +5028,21 @@ private:
|
||||||
" return -1;\n"
|
" return -1;\n"
|
||||||
"}\n");
|
"}\n");
|
||||||
ASSERT_EQUALS("[test.cpp:5]: (style) Condition 's.empty()' is always false\n", errout.str());
|
ASSERT_EQUALS("[test.cpp:5]: (style) Condition 's.empty()' is always false\n", errout.str());
|
||||||
|
|
||||||
|
check("void f(std::string& p) {\n"
|
||||||
|
" const std::string d{ \"abc\" };\n"
|
||||||
|
" p += d;\n"
|
||||||
|
" if(p.empty()) {}\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS("[test.cpp:4]: (style) Condition 'p.empty()' is always false\n", errout.str());
|
||||||
|
|
||||||
|
check("bool f(int i, FILE* fp) {\n"
|
||||||
|
" std::string s = \"abc\";\n"
|
||||||
|
" s += std::to_string(i);\n"
|
||||||
|
" s += \"\\n\";\n"
|
||||||
|
" return fwrite(s.c_str(), 1, s.length(), fp) == s.length();\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void alwaysTrueLoop()
|
void alwaysTrueLoop()
|
||||||
|
|
Loading…
Reference in New Issue