diff --git a/src/checkautovariables.cpp b/src/checkautovariables.cpp index 059aac4e5..168838f49 100644 --- a/src/checkautovariables.cpp +++ b/src/checkautovariables.cpp @@ -223,4 +223,70 @@ void CheckAutoVariables::autoVariables() +void CheckAutoVariables::returnPointerToLocalArray() +{ + bool infunc = false; + int indentlevel = 0; + std::list arrayVar; + for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) + { + // Is there a function declaration for a function that returns a pointer? + if (!infunc && (Token::Match(tok, "%type% * %var% (") || Token::Match(tok, "%type% * %var% :: %var% ("))) + { + for (const Token *tok2 = tok; tok2; tok2 = tok2->next()) + { + if (tok2->str() == ")") + { + tok = tok2; + break; + } + } + if (Token::simpleMatch(tok, ") {")) + { + infunc = true; + indentlevel = 0; + arrayVar.clear(); + } + } + + // Parsing a function that returns a pointer.. + if (infunc) + { + if (tok->str() == "{") + ++indentlevel; + else if (tok->str() == "}") + { + --indentlevel; + if (indentlevel <= 0) + infunc = false; + continue; + } + + // Declaring a local array.. + if (Token::Match(tok, "[;{}] %type% %var% [")) + { + arrayVar.push_back(tok->tokAt(2)->varId()); + } + + // Return pointer to local array variable.. + if (Token::Match(tok, "return %var% ;")) + { + unsigned int varid = tok->next()->varId(); + if (varid > 0 && std::find(arrayVar.begin(), arrayVar.end(), varid) != arrayVar.end()) + errorReturnPointerToLocalArray(tok); + } + } + + // Declaring array variable.. + + + } +} + +void CheckAutoVariables::errorReturnPointerToLocalArray(const Token *tok) +{ + reportError(tok, "error", "returnLocalVariable", "Returning pointer to local array variable"); +} + + diff --git a/src/checkautovariables.h b/src/checkautovariables.h index db0524fd4..689724b33 100644 --- a/src/checkautovariables.h +++ b/src/checkautovariables.h @@ -42,11 +42,15 @@ public: { CheckAutoVariables checkAutoVariables(tokenizer, settings, errorLogger); checkAutoVariables.autoVariables(); + checkAutoVariables.returnPointerToLocalArray(); } /** Check auto variables */ void autoVariables(); + /** Returning pointer to local array */ + void returnPointerToLocalArray(); + private: std::list fp_list; std::list vd_list; @@ -54,10 +58,17 @@ private: bool isAutoVar(const Token* t); void addVD(const Token* t); + + + + void errorReturnPointerToLocalArray(const Token *tok); + + void getErrorMessages() { std::cout << "===auto variables===" << "\n"; reportError(0, "error", "autoVariables", "Wrong assignement of an auto-variable to an effective parameter of a function"); + errorReturnPointerToLocalArray(0); } }; diff --git a/src/checkother.cpp b/src/checkother.cpp index 8e5c34d1f..033962306 100644 --- a/src/checkother.cpp +++ b/src/checkother.cpp @@ -864,68 +864,6 @@ void CheckOther::strPlusChar() -void CheckOther::returnPointerToStackData() -{ - bool infunc = false; - int indentlevel = 0; - std::list arrayVar; - for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) - { - // Is there a function declaration for a function that returns a pointer? - if (!infunc && (Token::Match(tok, "%type% * %var% (") || Token::Match(tok, "%type% * %var% :: %var% ("))) - { - for (const Token *tok2 = tok; tok2; tok2 = tok2->next()) - { - if (tok2->str() == ")") - { - tok = tok2; - break; - } - } - if (Token::simpleMatch(tok, ") {")) - { - infunc = true; - indentlevel = 0; - arrayVar.clear(); - } - } - - // Parsing a function that returns a pointer.. - if (infunc) - { - if (tok->str() == "{") - ++indentlevel; - else if (tok->str() == "}") - { - --indentlevel; - if (indentlevel <= 0) - infunc = false; - continue; - } - - // Declaring a local array.. - if (Token::Match(tok, "[;{}] %type% %var% [")) - { - arrayVar.push_back(tok->tokAt(2)->varId()); - } - - // Return pointer to local array variable.. - if (Token::Match(tok, "return %var% ;")) - { - unsigned int varid = tok->next()->varId(); - if (varid > 0 && std::find(arrayVar.begin(), arrayVar.end(), varid) != arrayVar.end()) - returnLocalVariable(tok); - } - } - - // Declaring array variable.. - - - } -} - - - void CheckOther::nullPointer() { // Locate insufficient null-pointer handling after loop @@ -1083,11 +1021,6 @@ void CheckOther::strPlusChar(const Token *tok) reportError(tok, "error", "strPlusChar", "Unusual pointer arithmetic"); } -void CheckOther::returnLocalVariable(const Token *tok) -{ - reportError(tok, "error", "returnLocalVariable", "Returning pointer to local array variable"); -} - void CheckOther::nullPointerError(const Token *tok) { reportError(tok, "error", "nullPointer", "Possible null pointer dereference"); diff --git a/src/checkother.h b/src/checkother.h index 47243e19d..6227c2802 100644 --- a/src/checkother.h +++ b/src/checkother.h @@ -67,7 +67,6 @@ public: } checkOther.strPlusChar(); - checkOther.returnPointerToStackData(); checkOther.InvalidFunctionUsage(); checkOther.nullPointer(); checkOther.CheckZeroDivision(); @@ -106,9 +105,6 @@ public: /** str plus char */ void strPlusChar(); - /** Returning pointer to local data */ - void returnPointerToStackData(); - /** possible null pointer dereference */ void nullPointer(); @@ -141,7 +137,6 @@ private: void variableScopeError(const Token *tok, const std::string &varname); void conditionAlwaysTrueFalse(const Token *tok, const std::string &truefalse); void strPlusChar(const Token *tok); - void returnLocalVariable(const Token *tok); void nullPointerError(const Token *tok); void zerodivError(const Token *tok); @@ -164,7 +159,6 @@ private: variableScopeError(0, "varname"); conditionAlwaysTrueFalse(0, "true/false"); strPlusChar(0); - returnLocalVariable(0); nullPointerError(0); zerodivError(0); } diff --git a/test/testautovariables.cpp b/test/testautovariables.cpp index d00c5040a..463fe90c7 100644 --- a/test/testautovariables.cpp +++ b/test/testautovariables.cpp @@ -54,9 +54,9 @@ private: // Check auto variables Settings settings; - settings._showAll = true; CheckAutoVariables checkAutoVariables(&tokenizer, &settings, this); checkAutoVariables.autoVariables(); + checkAutoVariables.returnPointerToLocalArray(); } void run() @@ -64,6 +64,9 @@ private: TEST_CASE(testautovar); TEST_CASE(testautovararray); TEST_CASE(testautovarreturn); + + TEST_CASE(returnLocalVariable1); + TEST_CASE(returnLocalVariable2); } @@ -99,6 +102,27 @@ private: "return #}"); ASSERT_EQUALS("[test.cpp:3]: (error) Return of the address of an auto-variable\n", errout.str()); } + + + void returnLocalVariable1() + { + check("char *foo()\n" + "{\n" + " char str[100] = {0};\n" + " return str;\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:4]: (error) Returning pointer to local array variable\n", errout.str()); + } + + void returnLocalVariable2() + { + check("std::string foo()\n" + "{\n" + " char str[100] = {0};\n" + " return str;\n" + "}\n"); + ASSERT_EQUALS("", errout.str()); + } }; REGISTER_TEST(TestAutoVariables) diff --git a/test/testother.cpp b/test/testother.cpp index b09ee78ff..83e7dc9a7 100644 --- a/test/testother.cpp +++ b/test/testother.cpp @@ -51,9 +51,6 @@ private: TEST_CASE(strPlusChar2); // "/usr" + ch TEST_CASE(strPlusChar3); // ok: path + "/sub" + '/' - TEST_CASE(returnLocalVariable1); - TEST_CASE(returnLocalVariable2); - TEST_CASE(varScope1); TEST_CASE(varScope2); TEST_CASE(varScope3); @@ -302,43 +299,6 @@ private: - void retVar(const char code[]) - { - // Tokenize.. - Tokenizer tokenizer; - std::istringstream istr(code); - tokenizer.tokenize(istr, "test.cpp"); - tokenizer.setVarId(); - - // Clear the error buffer.. - errout.str(""); - - // Check for redundant code.. - Settings settings; - CheckOther checkOther(&tokenizer, &settings, this); - checkOther.returnPointerToStackData(); - } - - void returnLocalVariable1() - { - retVar("char *foo()\n" - "{\n" - " char str[100] = {0};\n" - " return str;\n" - "}\n"); - ASSERT_EQUALS("[test.cpp:4]: (error) Returning pointer to local array variable\n", errout.str()); - } - - void returnLocalVariable2() - { - retVar("std::string foo()\n" - "{\n" - " char str[100] = {0};\n" - " return str;\n" - "}\n"); - ASSERT_EQUALS("", errout.str()); - } - void varScope(const char code[]) { // Tokenize..