From 65128a0bf9473bbe3a75274017b05506212be139 Mon Sep 17 00:00:00 2001 From: Paul Date: Thu, 16 Jul 2020 12:47:43 -0500 Subject: [PATCH 1/3] Fix issue 9783: wrong lifetime analysis temporary assigned to object --- lib/astutils.cpp | 8 +++----- lib/symboldatabase.cpp | 9 +++++++-- lib/valueflow.cpp | 19 +++++++++++++++++++ test/cfg/sqlite3.c | 1 - test/testautovariables.cpp | 2 +- test/teststl.cpp | 9 +++++++++ 6 files changed, 39 insertions(+), 9 deletions(-) diff --git a/lib/astutils.cpp b/lib/astutils.cpp index 4be2f8c7b52..2a499daf6f8 100644 --- a/lib/astutils.cpp +++ b/lib/astutils.cpp @@ -158,17 +158,15 @@ std::string astCanonicalType(const Token *expr) { if (!expr) return ""; - if (expr->variable()) { - const Variable *var = expr->variable(); + std::pair decl = Token::typeDecl(expr); + if (decl.first && decl.second) { std::string ret; - for (const Token *type = var->typeStartToken(); Token::Match(type,"%name%|::") && type != var->nameToken(); type = type->next()) { + for (const Token *type = decl.first; Token::Match(type,"%name%|::") && type != decl.second; type = type->next()) { if (!Token::Match(type, "const|static")) ret += type->str(); } return ret; - } - // TODO: handle expressions return ""; } diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index 0dcceb21d2c..90ef92acb94 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -5661,7 +5661,7 @@ static const Token * parsedecl(const Token *type, ValueType * const valuetype, V } else valuetype->type = ValueType::Type::RECORD; bool par = false; - while (Token::Match(type, "%name%|*|&|::|(") && !Token::Match(type, "typename|template") && + while (Token::Match(type, "%name%|*|&|::|(") && !Token::Match(type, "typename|template") && type->varId() == 0 && !type->variable() && !type->function()) { if (type->str() == "(") { if (Token::Match(type->link(), ") const| {")) @@ -6012,7 +6012,11 @@ void SymbolDatabase::setValueTypeInTokenList(bool reportDebugWarnings, Token *to const std::string& typestr(mSettings->library.returnValueType(tok->previous())); if (!typestr.empty()) { ValueType valuetype; - if (valuetype.fromLibraryType(typestr, mSettings)) { + TokenList tokenList(mSettings); + std::istringstream istr(typestr+";"); + tokenList.createTokens(istr); + if (parsedecl(tokenList.front(), &valuetype, mDefaultSignedness, mSettings)) { + valuetype.originalTypeName = typestr; setValueType(tok, valuetype); } } @@ -6045,6 +6049,7 @@ void SymbolDatabase::setValueTypeInTokenList(bool reportDebugWarnings, Token *to tokenList.simplifyPlatformTypes(); tokenList.simplifyStdType(); if (parsedecl(tokenList.front(), &vt, mDefaultSignedness, mSettings)) { + vt.originalTypeName = typestr; setValueType(tok, vt); } } diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index 2714291721f..eb600e23578 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -3031,6 +3031,21 @@ static bool isNotEqual(std::pair x, std::pair x, const std::string& y) +{ + TokenList tokenList(nullptr); + std::istringstream istr(y); + tokenList.createTokens(istr); + return isNotEqual(x, std::make_pair(tokenList.front(), tokenList.back())); +} +static bool isNotEqual(std::pair x, const ValueType* y) +{ + if (y == nullptr) + return false; + if (y->originalTypeName.empty()) + return false; + return isNotEqual(x, y->originalTypeName); +} bool isLifetimeBorrowed(const Token *tok, const Settings *settings) { @@ -3060,6 +3075,10 @@ bool isLifetimeBorrowed(const Token *tok, const Settings *settings) std::pair parentdecl = Token::typeDecl(tok->astParent()); if (isNotEqual(decl, parentdecl)) return false; + if (isNotEqual(decl, tok->astParent()->valueType())) + return false; + if (isNotEqual(parentdecl, tok->valueType())) + return false; } } } else if (Token::Match(tok->astParent()->tokAt(-3), "%var% . push_back|push_front|insert|push (") && diff --git a/test/cfg/sqlite3.c b/test/cfg/sqlite3.c index 0437951dd6c..4a9a1856c93 100644 --- a/test/cfg/sqlite3.c +++ b/test/cfg/sqlite3.c @@ -24,7 +24,6 @@ void validCode() { char * buf = sqlite3_malloc(10); - // cppcheck-suppress invalidPrintfArgType_uint printf("size: %ull\n", sqlite3_msize(buf)); sqlite3_free(buf); } diff --git a/test/testautovariables.cpp b/test/testautovariables.cpp index 18ababc8dd5..426d8107a47 100644 --- a/test/testautovariables.cpp +++ b/test/testautovariables.cpp @@ -975,7 +975,7 @@ class TestAutoVariables : public TestFixture { "std::string &f() {\n" " return hello().substr(1);\n" "}"); - ASSERT_EQUALS("", errout.str()); + ASSERT_EQUALS("[test.cpp:6]: (error) Reference to temporary returned.\n", errout.str()); check("class Foo;\n" "Foo hello() {\n" diff --git a/test/teststl.cpp b/test/teststl.cpp index e9e929a928c..3c9c4103dfe 100644 --- a/test/teststl.cpp +++ b/test/teststl.cpp @@ -4164,6 +4164,15 @@ class TestStl : public TestFixture { " v.push_back(\"y\");\n" "}\n",true); ASSERT_EQUALS("", errout.str()); + + // #9783 + check("std::string GetTaskIDPerUUID(int);\n" + "void InitializeJumpList(CString s);\n" + "void foo() {\n" + " CString sAppID = GetTaskIDPerUUID(123).c_str();\n" + " InitializeJumpList(sAppID);\n" + "}\n",true); + ASSERT_EQUALS("", errout.str()); } void invalidContainerLoop() { From 5224afa1470aa3a245812d368e5ab9a4dd0ed724 Mon Sep 17 00:00:00 2001 From: Paul Date: Mon, 31 Aug 2020 21:57:38 -0500 Subject: [PATCH 2/3] Encode xml string --- lib/symboldatabase.cpp | 2 +- lib/utils.h | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index 53323186b93..54eb4189a4b 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -6357,7 +6357,7 @@ std::string ValueType::dump() const ret << " valueType-typeScope=\"" << typeScope << '\"'; if (!originalTypeName.empty()) - ret << " valueType-originalTypeName=\"" << originalTypeName << '\"'; + ret << " valueType-originalTypeName=\"" << encodeXml(originalTypeName) << '\"'; return ret.str(); } diff --git a/lib/utils.h b/lib/utils.h index 059196427fd..ea67673d7be 100644 --- a/lib/utils.h +++ b/lib/utils.h @@ -98,6 +98,23 @@ inline static const char *getOrdinalText(int i) return "th"; } +inline std::string encodeXml(const std::string& data) +{ + std::string buffer; + buffer.reserve(data.size()); + for(size_t pos = 0; pos != data.size(); ++pos) { + switch(data[pos]) { + case '&': buffer.append("&"); break; + case '\"': buffer.append("""); break; + case '\'': buffer.append("'"); break; + case '<': buffer.append("<"); break; + case '>': buffer.append(">"); break; + default: buffer.append(&data[pos], 1); break; + } + } + return buffer; +} + CPPCHECKLIB int caseInsensitiveStringCompare(const std::string& lhs, const std::string& rhs); CPPCHECKLIB bool isValidGlobPattern(const std::string& pattern); From af953d1d89d23b955be60b2969b1c02f7dd9fc0d Mon Sep 17 00:00:00 2001 From: Paul Date: Tue, 1 Sep 2020 16:11:57 -0500 Subject: [PATCH 3/3] Use ErrorLogger::toxml instead --- lib/errorlogger.cpp | 3 +++ lib/symboldatabase.cpp | 2 +- lib/utils.h | 17 ----------------- 3 files changed, 4 insertions(+), 18 deletions(-) diff --git a/lib/errorlogger.cpp b/lib/errorlogger.cpp index 081c9effb3e..6ef4b28d4f3 100644 --- a/lib/errorlogger.cpp +++ b/lib/errorlogger.cpp @@ -682,6 +682,9 @@ std::string ErrorLogger::toxml(const std::string &str) case '\"': xml << """; break; + case '\'': + xml << "'"; + break; case '\0': xml << "\\0"; break; diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index 54eb4189a4b..64d7d8575e2 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -6357,7 +6357,7 @@ std::string ValueType::dump() const ret << " valueType-typeScope=\"" << typeScope << '\"'; if (!originalTypeName.empty()) - ret << " valueType-originalTypeName=\"" << encodeXml(originalTypeName) << '\"'; + ret << " valueType-originalTypeName=\"" << ErrorLogger::toxml(originalTypeName) << '\"'; return ret.str(); } diff --git a/lib/utils.h b/lib/utils.h index ea67673d7be..059196427fd 100644 --- a/lib/utils.h +++ b/lib/utils.h @@ -98,23 +98,6 @@ inline static const char *getOrdinalText(int i) return "th"; } -inline std::string encodeXml(const std::string& data) -{ - std::string buffer; - buffer.reserve(data.size()); - for(size_t pos = 0; pos != data.size(); ++pos) { - switch(data[pos]) { - case '&': buffer.append("&"); break; - case '\"': buffer.append("""); break; - case '\'': buffer.append("'"); break; - case '<': buffer.append("<"); break; - case '>': buffer.append(">"); break; - default: buffer.append(&data[pos], 1); break; - } - } - return buffer; -} - CPPCHECKLIB int caseInsensitiveStringCompare(const std::string& lhs, const std::string& rhs); CPPCHECKLIB bool isValidGlobPattern(const std::string& pattern);