diff --git a/lib/checkstl.cpp b/lib/checkstl.cpp index e7c10febb..5c3016292 100644 --- a/lib/checkstl.cpp +++ b/lib/checkstl.cpp @@ -1232,7 +1232,9 @@ static bool hasArrayEndParen(const Token *tok1) void CheckStl::checkAutoPointer() { std::set autoPtrVarId; + std::map mallocVarId; // variables allocated by the malloc-like function static const char STL_CONTAINER_LIST[] = "array|bitset|deque|list|forward_list|map|multimap|multiset|priority_queue|queue|set|stack|vector|hash_map|hash_multimap|hash_set|unordered_map|unordered_multimap|unordered_set|unordered_multiset|basic_string"; + const int malloc = _settings->library.alloc("malloc"); // allocation function, which are not compatible with auto_ptr for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) { if (Token::simpleMatch(tok, "auto_ptr <")) { @@ -1247,6 +1249,17 @@ void CheckStl::checkAutoPointer() if (Token::Match(tok3, "( new %type%") && hasArrayEndParen(tok3)) { autoPointerArrayError(tok2->next()); } + if (Token::Match(tok3, "( %name% (") && malloc && _settings->library.alloc(tok3->next()) == malloc) { + // malloc-like function allocated memory passed to the auto_ptr constructor -> error + autoPointerMallocError(tok2->next(), tok3->next()->str()); + } + if (Token::Match(tok3, "( %var%")) { + std::map::const_iterator it = mallocVarId.find(tok3->next()->varId()); + if (it != mallocVarId.cend()) { + // pointer on the memory allocated by malloc used in the auto pointer constructor -> error + autoPointerMallocError(tok2->next(), it->second); + } + } while (tok3 && tok3->str() != ";") { tok3 = tok3->next(); } @@ -1280,6 +1293,21 @@ void CheckStl::checkAutoPointer() if (iter != autoPtrVarId.end()) { autoPointerArrayError(tok); } + } else if (Token::Match(tok, "%var% = %name% (") && malloc && _settings->library.alloc(tok->tokAt(2)) == malloc) { + // C library function like 'malloc' used together with auto pointer -> error + std::set::const_iterator iter = autoPtrVarId.find(tok->varId()); + if (iter != autoPtrVarId.end()) { + autoPointerMallocError(tok, tok->strAt(2)); + } else if (tok->varId()) { + // it is not an auto pointer variable and it is allocated by malloc like function. + mallocVarId.insert(std::make_pair(tok->varId(), tok->strAt(2))); + } + } else if (Token::Match(tok, "%var% . reset ( %name% (") && malloc && _settings->library.alloc(tok->tokAt(4)) == malloc) { + // C library function like 'malloc' used when resetting auto pointer -> error + std::set::const_iterator iter = autoPtrVarId.find(tok->varId()); + if (iter != autoPtrVarId.end()) { + autoPointerMallocError(tok, tok->strAt(4)); + } } } } @@ -1310,6 +1338,13 @@ void CheckStl::autoPointerArrayError(const Token *tok) ); } +void CheckStl::autoPointerMallocError(const Token *tok, const std::string& allocFunction) +{ + const std::string summary = "Object pointed by an 'auto_ptr' is destroyed using operator 'delete'. You should not use 'auto_ptr' for pointers obtained with function '" + allocFunction + "'."; + const std::string verbose = summary + " This means that you should only use 'auto_ptr' for pointers obtained with operator 'new'. This excludes use C library allocation functions (for example '" + allocFunction + "'), which must be deallocated by the appropriate C library function."; + reportError(tok, Severity::error, "useAutoPointerMalloc", summary + "\n" + verbose); +} + void CheckStl::uselessCalls() { // THIS ARRAY MUST BE ORDERED ALPHABETICALLY diff --git a/lib/checkstl.h b/lib/checkstl.h index 133744817..dd8c5f09c 100644 --- a/lib/checkstl.h +++ b/lib/checkstl.h @@ -178,6 +178,7 @@ private: void autoPointerError(const Token *tok); void autoPointerContainerError(const Token *tok); void autoPointerArrayError(const Token *tok); + void autoPointerMallocError(const Token *tok, const std::string& allocFunction); void uselessCallsReturnValueError(const Token *tok, const std::string &varname, const std::string &function); void uselessCallsSwapError(const Token *tok, const std::string &varname); @@ -210,6 +211,7 @@ private: c.autoPointerError(0); c.autoPointerContainerError(0); c.autoPointerArrayError(0); + c.autoPointerMallocError(0, "malloc"); c.uselessCallsReturnValueError(0, "str", "find"); c.uselessCallsSwapError(0, "str"); c.uselessCallsSubstrError(0, false); diff --git a/test/teststl.cpp b/test/teststl.cpp index be2d448c4..4217f07f3 100644 --- a/test/teststl.cpp +++ b/test/teststl.cpp @@ -2298,6 +2298,52 @@ private: " auto_ptr_array domainName(new char[42]);\n" "}"); ASSERT_EQUALS("", errout.str()); + + // ticket #749 + check("int main()\n" + "{\n" + " int *i = malloc(sizeof(int));\n" + " auto_ptr x(i);\n" + "}"); + ASSERT_EQUALS("[test.cpp:4]: (error) Object pointed by an 'auto_ptr' is destroyed using operator 'delete'. You should not use 'auto_ptr' for pointers obtained with function 'malloc'.\n", errout.str()); + + check("int main()\n" + "{\n" + " auto_ptr x((int*)malloc(sizeof(int)*4));\n" + "}"); + ASSERT_EQUALS("[test.cpp:3]: (error) Object pointed by an 'auto_ptr' is destroyed using operator 'delete'. You should not use 'auto_ptr' for pointers obtained with function 'malloc'.\n", errout.str()); + + check("int main()\n" + "{\n" + " auto_ptr b(static_cast(malloc(sizeof(int)*4)));\n" + "}"); + ASSERT_EQUALS("[test.cpp:3]: (error) Object pointed by an 'auto_ptr' is destroyed using operator 'delete'. You should not use 'auto_ptr' for pointers obtained with function 'malloc'.\n", errout.str()); + + check("int main()\n" + "{\n" + " auto_ptr x = (int*)malloc(sizeof(int)*4);\n" + "}"); + ASSERT_EQUALS("[test.cpp:3]: (error) Object pointed by an 'auto_ptr' is destroyed using operator 'delete'. You should not use 'auto_ptr' for pointers obtained with function 'malloc'.\n", errout.str()); + + check("int main()\n" + "{\n" + " auto_ptr x = static_cast(malloc(sizeof(int)*4));\n" + "}"); + ASSERT_EQUALS("[test.cpp:3]: (error) Object pointed by an 'auto_ptr' is destroyed using operator 'delete'. You should not use 'auto_ptr' for pointers obtained with function 'malloc'.\n", errout.str()); + + check("int main()\n" + "{\n" + " auto_ptr x;\n" + " x.reset((int*)malloc(sizeof(int)*4));\n" + "}"); + ASSERT_EQUALS("[test.cpp:4]: (error) Object pointed by an 'auto_ptr' is destroyed using operator 'delete'. You should not use 'auto_ptr' for pointers obtained with function 'malloc'.\n", errout.str()); + + check("int main()\n" + "{\n" + " auto_ptr x;\n" + " x.reset(static_cast(malloc(sizeof(int)*4)));\n" + "}"); + ASSERT_EQUALS("[test.cpp:4]: (error) Object pointed by an 'auto_ptr' is destroyed using operator 'delete'. You should not use 'auto_ptr' for pointers obtained with function 'malloc'.\n", errout.str()); } void uselessCalls() {