From 40147c1e4be439a6096e9c6b09d7f6c07dc85a17 Mon Sep 17 00:00:00 2001 From: Paul Fultz II Date: Tue, 25 Jan 2022 23:42:41 -0600 Subject: [PATCH] Fix 10719: Crash in valueFlowIterators() (#3756) * Fix 10719: Crash in valueFlowIterators() * Format --- lib/valueflow.cpp | 38 ++++++++++++++++++++++++-------------- test/testvalueflow.cpp | 11 +++++++++++ 2 files changed, 35 insertions(+), 14 deletions(-) diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index af217dc7d..b0a87da43 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -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) && 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; if (yields == Library::Container::Yield::SIZE) { ValueFlow::Value v(value); @@ -1564,7 +1564,7 @@ static void valueFlowImpossibleValues(TokenList* tokenList, const Settings* sett value.setImpossible(); setTokenValue(tok->next(), value, settings); } 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) continue; 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) { - if (!tok->valueType() || !tok->valueType()->container) + if (!tok->valueType()) + return false; + if (!astIsContainer(tok)) return false; // If we are accessing an element then we are not changing the container size 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) return false; } @@ -6903,22 +6905,26 @@ struct ContainerExpressionAnalyzer : ExpressionAnalyzer { return Action::None; if (!getValue(tok)) return Action::None; - if (!tok->valueType() || !tok->valueType()->container) + if (!tok->valueType()) + return Action::None; + if (!astIsContainer(tok)) return Action::None; 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(); if (rhs->tokType() == Token::eString) 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) { return rhsval.isKnown() && rhsval.isContainerSizeValue(); })) return Action::Read | Action::Write | Action::Incremental; } } 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) { std::vector args = getArguments(tok->tokAt(3)); if (args.size() < 2) @@ -6935,15 +6941,19 @@ struct ContainerExpressionAnalyzer : ExpressionAnalyzer { return; if (!tok->astParent()) return; - const Token* parent = tok->astParent(); - if (!tok->valueType() || !tok->valueType()->container) + if (!tok->valueType()) 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 Library::Container* rhsContainer = getLibraryContainer(rhs); if (rhs->tokType() == Token::eString) 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()) { if (rhsval.isKnown() && rhsval.isContainerSizeValue()) { val->intvalue += rhsval.intvalue; @@ -6951,7 +6961,7 @@ struct ContainerExpressionAnalyzer : ExpressionAnalyzer { } } } 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) val->intvalue++; if (action == Library::Container::Action::POP) @@ -7159,7 +7169,7 @@ static void valueFlowIterators(TokenList *tokenlist, const Settings *settings) if (!astIsContainer(tok)) continue; 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); v.setKnown(); if (yield == Library::Container::Yield::START_ITERATOR) { diff --git a/test/testvalueflow.cpp b/test/testvalueflow.cpp index fdec94c65..4819ca883 100644 --- a/test/testvalueflow.cpp +++ b/test/testvalueflow.cpp @@ -6062,6 +6062,17 @@ private: "}\n"; valueOfTok(code, "x"); + code = "struct a {\n" + " void b();\n" + "};\n" + "void d(std::vector 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" "const int& f(int, const int& y) {\n" " return y;\n"