From 8fa7dd0fe0ba6c8b576ce2a9e7fb3ba0bb71fa64 Mon Sep 17 00:00:00 2001 From: Paul Fultz II Date: Mon, 10 Feb 2020 11:01:11 -0600 Subject: [PATCH] Fix issue 9595: False positive: Using pointer to temporary doesn't account for const ref extended temporary lifetimes (#2525) --- lib/astutils.cpp | 4 ++-- lib/astutils.h | 2 +- lib/valueflow.cpp | 2 +- test/testautovariables.cpp | 7 +++++++ 4 files changed, 11 insertions(+), 4 deletions(-) diff --git a/lib/astutils.cpp b/lib/astutils.cpp index c0f17766b..a1bce083e 100644 --- a/lib/astutils.cpp +++ b/lib/astutils.cpp @@ -220,7 +220,7 @@ const Token * astIsVariableComparison(const Token *tok, const std::string &comp, return ret; } -bool isTemporary(bool cpp, const Token* tok, const Library* library) +bool isTemporary(bool cpp, const Token* tok, const Library* library, bool unknown) { if (!tok) return false; @@ -251,7 +251,7 @@ bool isTemporary(bool cpp, const Token* tok, const Library* library) std::string returnType = library->returnValueType(ftok); return !returnType.empty() && returnType.back() != '&'; } else { - return false; + return unknown; } } return true; diff --git a/lib/astutils.h b/lib/astutils.h index 9b9b11fed..990e42357 100644 --- a/lib/astutils.h +++ b/lib/astutils.h @@ -87,7 +87,7 @@ std::string astCanonicalType(const Token *expr); /** Is given syntax tree a variable comparison against value */ const Token * astIsVariableComparison(const Token *tok, const std::string &comp, const std::string &rhs, const Token **vartok=nullptr); -bool isTemporary(bool cpp, const Token* tok, const Library* library); +bool isTemporary(bool cpp, const Token* tok, const Library* library, bool unknown = false); const Token * nextAfterAstRightmostLeaf(const Token * tok); diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index cf54603ae..68608f769 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -3231,7 +3231,7 @@ std::vector getLifetimeTokens(const Token* tok, ValueFlow::Value: } else if (Token::simpleMatch(var->declEndToken(), "=")) { errorPath.emplace_back(var->declEndToken(), "Assigned to reference."); const Token *vartok = var->declEndToken()->astOperand2(); - if (vartok == tok || (var->isConst() && isTemporary(true, vartok, nullptr))) + if (vartok == tok || (var->isConst() && isTemporary(true, vartok, nullptr, true))) return {{tok, true, std::move(errorPath)}}; if (vartok) return getLifetimeTokens(vartok, std::move(errorPath), depth - 1); diff --git a/test/testautovariables.cpp b/test/testautovariables.cpp index ebc1897c2..88fee3eb8 100644 --- a/test/testautovariables.cpp +++ b/test/testautovariables.cpp @@ -2501,6 +2501,13 @@ private: ASSERT_EQUALS( "[test.cpp:3] -> [test.cpp:4]: (error) Using iterator to temporary.\n", errout.str()); + + check("std::string f() {\n" + " std::stringstream tmp;\n" + " const std::string &str = tmp.str();\n" + " return std::string(str.c_str(), 1);\n" + "}\n"); + ASSERT_EQUALS("", errout.str()); } void invalidLifetime() {