From a5b0a1c9e2279f9e0863596405d95752a19b8d28 Mon Sep 17 00:00:00 2001 From: Paul Date: Mon, 10 Aug 2020 20:08:49 -0500 Subject: [PATCH] Evaluate container size in program memory --- lib/programmemory.cpp | 28 ++++++++++++++++++++++++++++ lib/programmemory.h | 2 ++ lib/valueflow.cpp | 2 ++ test/teststl.cpp | 10 ++++++++++ 4 files changed, 42 insertions(+) diff --git a/lib/programmemory.cpp b/lib/programmemory.cpp index faf086b5e..9c7fd09c1 100644 --- a/lib/programmemory.cpp +++ b/lib/programmemory.cpp @@ -34,6 +34,15 @@ bool ProgramMemory::getTokValue(nonneg int varid, const Token** result) const return found; } +bool ProgramMemory::getContainerSizeValue(nonneg int varid, MathLib::bigint* result) const +{ + const ProgramMemory::Map::const_iterator it = values.find(varid); + const bool found = it != values.end() && it->second.isContainerSizeValue(); + if (found) + *result = it->second.intvalue; + return found; +} + void ProgramMemory::setUnknown(nonneg int varid) { values[varid].valueType = ValueFlow::Value::ValueType::UNINIT; @@ -534,6 +543,25 @@ void execute(const Token *expr, else *error = true; } + else if (Token::Match(expr->tokAt(-3), "%var% . %name% (")) { + const Token* containerTok = expr->tokAt(-3); + if (astIsContainer(containerTok) && containerTok->varId() > 0) { + Library::Container::Yield yield = containerTok->valueType()->container->getYield(expr->strAt(-1)); + if (yield == Library::Container::Yield::SIZE) { + if (!programMemory->getContainerSizeValue(containerTok->varId(), result)) + *error = true; + } else if (yield == Library::Container::Yield::EMPTY) { + MathLib::bigint size = 0; + if (!programMemory->getContainerSizeValue(containerTok->varId(), &size)) + *error = true; + *result = (size == 0); + } else { + *error = true; + } + } else { + *error = true; + } + } else *error = true; diff --git a/lib/programmemory.h b/lib/programmemory.h index 5c4ed972d..339026955 100644 --- a/lib/programmemory.h +++ b/lib/programmemory.h @@ -19,6 +19,8 @@ struct ProgramMemory { bool getIntValue(nonneg int varid, MathLib::bigint* result) const; void setIntValue(nonneg int varid, MathLib::bigint value); + bool getContainerSizeValue(nonneg int varid, MathLib::bigint* result) const; + void setUnknown(nonneg int varid); bool getTokValue(nonneg int varid, const Token** result) const; diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index 8aedacfb6..d58d08689 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -5773,6 +5773,8 @@ static bool isContainerSizeChanged(const Token *tok, int depth) return true; if (Token::Match(tok, "%name% %assign%|<<")) return true; + if (Token::Match(tok, "%var% [") && tok->valueType()->container->stdAssociativeLike) + return true; if (Token::Match(tok, "%name% . %name% (")) { Library::Container::Action action = tok->valueType()->container->getAction(tok->strAt(2)); Library::Container::Yield yield = tok->valueType()->container->getYield(tok->strAt(2)); diff --git a/test/teststl.cpp b/test/teststl.cpp index 2a3cfb023..ae812f3bf 100644 --- a/test/teststl.cpp +++ b/test/teststl.cpp @@ -335,6 +335,16 @@ private: " x[0] = 0;\n" "}\n"); ASSERT_EQUALS("", errout.str()); + + checkNormal("void f(bool b) {\n" + " std::vector x;\n" + " if (b)\n" + " x.push_back(1);\n" + " if (x.size() < 2)\n" + " return;\n" + " x[0] = 2;\n" + "}\n"); + ASSERT_EQUALS("", errout.str()); } void outOfBoundsIndexExpression() {