From bbe6157e1638630f3360714fee3790121199d8c4 Mon Sep 17 00:00:00 2001 From: Paul Fultz II Date: Sat, 23 May 2020 16:12:00 -0500 Subject: [PATCH] Fix issue 9712: False positive: Returning pointer to local variable when return line implicitly cast to return type (#2662) --- lib/valueflow.cpp | 52 +++++++++++++++++++++++++++++++++++--- test/testautovariables.cpp | 7 +++++ 2 files changed, 55 insertions(+), 4 deletions(-) diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index a10494509..940b4b0bc 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -2977,11 +2977,47 @@ static bool isLifetimeBorrowed(const ValueType *vt, const ValueType *vtParent) return true; if (vtParent->pointer < vt->pointer && vtParent->isIntegral()) return true; + if (vtParent->str() == vt->str()) + return true; } return false; } +static const Token* skipCVRefs(const Token* tok, const Token* endTok) +{ + while(tok != endTok && Token::Match(tok, "const|volatile|auto|&|&&")) + tok = tok->next(); + return tok; +} + +static bool isNotEqual(std::pair x, std::pair y) +{ + const Token* start1 = x.first; + const Token* start2 = y.first; + if (start1 == nullptr || start2 == nullptr) + return false; + while(start1 != x.second && start2 != y.second) { + const Token* tok1 = skipCVRefs(start1, x.second); + if (tok1 != start1) { + start1 = tok1; + continue; + } + const Token* tok2 = skipCVRefs(start2, y.second); + if (tok2 != start2) { + start2 = tok2; + continue; + } + if (start1->str() != start2->str()) + return true; + start1 = start1->next(); + start2 = start2->next(); + } + start1 = skipCVRefs(start1, x.second); + start2 = skipCVRefs(start2, y.second); + return !(start1 == x.second && start2 == y.second); +} + bool isLifetimeBorrowed(const Token *tok, const Settings *settings) { if (!tok) @@ -2999,10 +3035,18 @@ bool isLifetimeBorrowed(const Token *tok, const Settings *settings) if (isLifetimeOwned(vt, vtParent)) return false; } - const Type *t = Token::typeOf(tok); - const Type *parentT = Token::typeOf(tok->astParent()); - if (t && parentT && t->classDef && parentT->classDef && t->classDef != parentT->classDef) { - return false; + if (Token::Match(tok->astParent(), "return|(|{|%assign%")) { + const Type *t = Token::typeOf(tok); + const Type *parentT = Token::typeOf(tok->astParent()); + if (t && parentT) { + if (t->classDef && parentT->classDef && t->classDef != parentT->classDef) + return false; + } else { + std::pair decl = Token::typeDecl(tok); + std::pair parentdecl = Token::typeDecl(tok->astParent()); + if (isNotEqual(decl, parentdecl)) + return false; + } } } else if (Token::Match(tok->astParent()->tokAt(-3), "%var% . push_back|push_front|insert|push (") && astIsContainer(tok->astParent()->tokAt(-3))) { diff --git a/test/testautovariables.cpp b/test/testautovariables.cpp index 8d7634dab..242bae115 100644 --- a/test/testautovariables.cpp +++ b/test/testautovariables.cpp @@ -2320,6 +2320,13 @@ private: " return &y.x[i];\n" "}\n"); ASSERT_EQUALS("", errout.str()); + + // #9712 + check("std::string f(const char *str) {\n" + " char value[256];\n" + " return value;\n" + "}\n"); + ASSERT_EQUALS("", errout.str()); } void danglingLifetimeFunction() {