Fix 10719: Crash in valueFlowIterators() (#3756)

* Fix 10719: Crash in valueFlowIterators()

* Format
This commit is contained in:
Paul Fultz II 2022-01-25 23:42:41 -06:00 committed by GitHub
parent 1a949c00b0
commit 40147c1e4b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 35 additions and 14 deletions

View File

@ -526,7 +526,7 @@ static void setTokenValue(Token* tok, ValueFlow::Value value, const Settings* se
else if (Token::Match(parent, ". %name% (") && parent->astParent() == parent->tokAt(2) && else if (Token::Match(parent, ". %name% (") && parent->astParent() == parent->tokAt(2) &&
parent->astOperand1() && parent->astOperand1()->valueType()) { parent->astOperand1() && parent->astOperand1()->valueType()) {
const Library::Container *c = parent->astOperand1()->valueType()->container; const Library::Container* c = getLibraryContainer(parent->astOperand1());
const Library::Container::Yield yields = c ? c->getYield(parent->strAt(1)) : Library::Container::Yield::NO_YIELD; const Library::Container::Yield yields = c ? c->getYield(parent->strAt(1)) : Library::Container::Yield::NO_YIELD;
if (yields == Library::Container::Yield::SIZE) { if (yields == Library::Container::Yield::SIZE) {
ValueFlow::Value v(value); ValueFlow::Value v(value);
@ -1564,7 +1564,7 @@ static void valueFlowImpossibleValues(TokenList* tokenList, const Settings* sett
value.setImpossible(); value.setImpossible();
setTokenValue(tok->next(), value, settings); setTokenValue(tok->next(), value, settings);
} else if (Token::Match(tok, ". data|c_str (") && astIsContainerOwned(tok->astOperand1())) { } else if (Token::Match(tok, ". data|c_str (") && astIsContainerOwned(tok->astOperand1())) {
const Library::Container* container = tok->astOperand1()->valueType()->container; const Library::Container* container = getLibraryContainer(tok->astOperand1());
if (!container) if (!container)
continue; continue;
if (!container->stdStringLike) if (!container->stdStringLike)
@ -6838,11 +6838,13 @@ static bool isContainerSizeChanged(nonneg int varId,
static bool isContainerSizeChangedByFunction(const Token* tok, const Settings* settings = nullptr, int depth = 20) static bool isContainerSizeChangedByFunction(const Token* tok, const Settings* settings = nullptr, int depth = 20)
{ {
if (!tok->valueType() || !tok->valueType()->container) if (!tok->valueType())
return false;
if (!astIsContainer(tok))
return false; return false;
// If we are accessing an element then we are not changing the container size // If we are accessing an element then we are not changing the container size
if (Token::Match(tok, "%name% . %name% (")) { if (Token::Match(tok, "%name% . %name% (")) {
Library::Container::Yield yield = tok->valueType()->container->getYield(tok->strAt(2)); Library::Container::Yield yield = getLibraryContainer(tok)->getYield(tok->strAt(2));
if (yield != Library::Container::Yield::NO_YIELD) if (yield != Library::Container::Yield::NO_YIELD)
return false; return false;
} }
@ -6903,22 +6905,26 @@ struct ContainerExpressionAnalyzer : ExpressionAnalyzer {
return Action::None; return Action::None;
if (!getValue(tok)) if (!getValue(tok))
return Action::None; return Action::None;
if (!tok->valueType() || !tok->valueType()->container) if (!tok->valueType())
return Action::None;
if (!astIsContainer(tok))
return Action::None; return Action::None;
const Token* parent = tok->astParent(); const Token* parent = tok->astParent();
const Library::Container* container = getLibraryContainer(tok);
if (tok->valueType()->container->stdStringLike && Token::simpleMatch(parent, "+=") && astIsLHS(tok) && parent->astOperand2()) { if (container->stdStringLike && Token::simpleMatch(parent, "+=") && astIsLHS(tok) && parent->astOperand2()) {
const Token* rhs = parent->astOperand2(); const Token* rhs = parent->astOperand2();
if (rhs->tokType() == Token::eString) if (rhs->tokType() == Token::eString)
return Action::Read | Action::Write | Action::Incremental; return Action::Read | Action::Write | Action::Incremental;
if (rhs->valueType() && rhs->valueType()->container && rhs->valueType()->container->stdStringLike) { const Library::Container* rhsContainer = getLibraryContainer(rhs);
if (rhsContainer && rhsContainer->stdStringLike) {
if (std::any_of(rhs->values().begin(), rhs->values().end(), [&](const ValueFlow::Value &rhsval) { if (std::any_of(rhs->values().begin(), rhs->values().end(), [&](const ValueFlow::Value &rhsval) {
return rhsval.isKnown() && rhsval.isContainerSizeValue(); return rhsval.isKnown() && rhsval.isContainerSizeValue();
})) }))
return Action::Read | Action::Write | Action::Incremental; return Action::Read | Action::Write | Action::Incremental;
} }
} else if (Token::Match(tok, "%name% . %name% (")) { } else if (Token::Match(tok, "%name% . %name% (")) {
Library::Container::Action action = tok->valueType()->container->getAction(tok->strAt(2)); Library::Container::Action action = container->getAction(tok->strAt(2));
if (action == Library::Container::Action::PUSH || action == Library::Container::Action::POP) { if (action == Library::Container::Action::PUSH || action == Library::Container::Action::POP) {
std::vector<const Token*> args = getArguments(tok->tokAt(3)); std::vector<const Token*> args = getArguments(tok->tokAt(3));
if (args.size() < 2) if (args.size() < 2)
@ -6935,15 +6941,19 @@ struct ContainerExpressionAnalyzer : ExpressionAnalyzer {
return; return;
if (!tok->astParent()) if (!tok->astParent())
return; return;
const Token* parent = tok->astParent(); if (!tok->valueType())
if (!tok->valueType() || !tok->valueType()->container)
return; return;
if (!astIsContainer(tok))
return;
const Token* parent = tok->astParent();
const Library::Container* container = getLibraryContainer(tok);
if (tok->valueType()->container->stdStringLike && Token::simpleMatch(parent, "+=") && parent->astOperand2()) { if (container->stdStringLike && Token::simpleMatch(parent, "+=") && parent->astOperand2()) {
const Token* rhs = parent->astOperand2(); const Token* rhs = parent->astOperand2();
const Library::Container* rhsContainer = getLibraryContainer(rhs);
if (rhs->tokType() == Token::eString) if (rhs->tokType() == Token::eString)
val->intvalue += Token::getStrLength(rhs); val->intvalue += Token::getStrLength(rhs);
else if (rhs->valueType() && rhs->valueType()->container && rhs->valueType()->container->stdStringLike) { else if (rhsContainer && rhsContainer->stdStringLike) {
for (const ValueFlow::Value &rhsval : rhs->values()) { for (const ValueFlow::Value &rhsval : rhs->values()) {
if (rhsval.isKnown() && rhsval.isContainerSizeValue()) { if (rhsval.isKnown() && rhsval.isContainerSizeValue()) {
val->intvalue += rhsval.intvalue; val->intvalue += rhsval.intvalue;
@ -6951,7 +6961,7 @@ struct ContainerExpressionAnalyzer : ExpressionAnalyzer {
} }
} }
} else if (Token::Match(tok, "%name% . %name% (")) { } else if (Token::Match(tok, "%name% . %name% (")) {
Library::Container::Action action = tok->valueType()->container->getAction(tok->strAt(2)); Library::Container::Action action = container->getAction(tok->strAt(2));
if (action == Library::Container::Action::PUSH) if (action == Library::Container::Action::PUSH)
val->intvalue++; val->intvalue++;
if (action == Library::Container::Action::POP) if (action == Library::Container::Action::POP)
@ -7159,7 +7169,7 @@ static void valueFlowIterators(TokenList *tokenlist, const Settings *settings)
if (!astIsContainer(tok)) if (!astIsContainer(tok))
continue; continue;
if (Token::Match(tok->astParent(), ". %name% (")) { if (Token::Match(tok->astParent(), ". %name% (")) {
Library::Container::Yield yield = tok->valueType()->container->getYield(tok->astParent()->strAt(1)); Library::Container::Yield yield = getLibraryContainer(tok)->getYield(tok->astParent()->strAt(1));
ValueFlow::Value v(0); ValueFlow::Value v(0);
v.setKnown(); v.setKnown();
if (yield == Library::Container::Yield::START_ITERATOR) { if (yield == Library::Container::Yield::START_ITERATOR) {

View File

@ -6062,6 +6062,17 @@ private:
"}\n"; "}\n";
valueOfTok(code, "x"); valueOfTok(code, "x");
code = "struct a {\n"
" void b();\n"
"};\n"
"void d(std::vector<a> c) {\n"
" a *e;\n"
" for (auto &child : c)\n"
" e = &child;\n"
" (*e).b();\n"
"}\n";
valueOfTok(code, "e");
code = "const int& f(int, const int& y = 0);\n" code = "const int& f(int, const int& y = 0);\n"
"const int& f(int, const int& y) {\n" "const int& f(int, const int& y) {\n"
" return y;\n" " return y;\n"