From 85dcb14813814a834f02068cd22c63feafde7109 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Sat, 11 Jan 2014 14:31:51 +0100 Subject: [PATCH] value flow: bailout in valueFlowBeforeCondition if variable can be assigned by subfunction --- lib/valueflow.cpp | 35 +++++++++++++++++++++++++++++++++++ test/testvalueflow.cpp | 12 +++++++++++- 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index 898fdd918..364813fae 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -44,6 +44,34 @@ static void bailout(TokenList *tokenlist, ErrorLogger *errorLogger, const Token errorLogger->reportErr(errmsg); } +static bool bailoutFunctionPar(const Token *tok) +{ + // passing variable to subfunction? + const bool addr = tok && Token::Match(tok->previous(), "&"); + if (!tok || !Token::Match(tok->tokAt(addr?-2:-1), "[(,] &| %var% [,)]")) + return false; + + // goto start of function call and get argnr + unsigned int argnr = 0; + while (tok && tok->str() != "(") { + if (tok->str() == ",") + ++argnr; + else if (tok->str() == ")") + tok = tok->link(); + tok = tok->previous(); + } + tok = tok ? tok->previous() : NULL; + if (!Token::Match(tok,"%var% (")) + return false; // not a function => dont bailout + + if (!tok->function()) + return true; // unknown function bailout + + const Variable *arg = tok->function()->getArgumentVar(argnr); + + return arg && !arg->isConst() && arg->isReference(); +} + static void valueFlowBeforeCondition(TokenList *tokenlist, ErrorLogger *errorLogger, const Settings *settings) { for (Token *tok = tokenlist->front(); tok; tok = tok->next()) { @@ -114,6 +142,13 @@ static void valueFlowBeforeCondition(TokenList *tokenlist, ErrorLogger *errorLog break; } + // assigned by subfunction? + if (bailoutFunctionPar(tok2)) { + if (settings->debugwarnings) + bailout(tokenlist, errorLogger, tok2, "possible assignment of " + tok2->str() + " by subfunction"); + break; + } + // skip if variable is conditionally used in ?: expression. const Token *parent = tok2; while (parent && !Token::Match(parent, "%oror%|&&|?|:")) { diff --git a/test/testvalueflow.cpp b/test/testvalueflow.cpp index 596198aa4..4d934207a 100644 --- a/test/testvalueflow.cpp +++ b/test/testvalueflow.cpp @@ -39,7 +39,7 @@ private: TEST_CASE(valueFlowSubFunction); } - bool testValueOfX(const char code[], unsigned int linenr, int value) { + bool testValueOfX(const std::string &code, unsigned int linenr, int value) { Settings settings; settings.valueFlow = true; // temporary flag @@ -113,6 +113,16 @@ private: ASSERT_EQUALS(true, testValueOfX(code, 2U, 0)); ASSERT_EQUALS(false, testValueOfX(code, 3U, 0)); + // function calls + code = "void f(int x) {\n" + " a = x;\n" + " setx(x);\n" + " if (x == 1) {}\n" + "}"; + ASSERT_EQUALS(true, testValueOfX(std::string("void setx(int x);")+code, 2U, 1)); + ASSERT_EQUALS(false, testValueOfX(std::string("void setx(int &x);")+code, 2U, 1)); + ASSERT_EQUALS(false, testValueOfX(code, 2U, 1)); + // bailout: ?: bailout("void f(int x) {\n" " y = ((x<0) ? x : ((x==2)?3:4));\n"