From 7e5d8e42d4c4ab41ea709b5ac1f76b35ce59efd7 Mon Sep 17 00:00:00 2001 From: Greg Hewgill Date: Sat, 19 Feb 2011 16:10:50 +1300 Subject: [PATCH 01/27] remove stray BOM from source file --- lib/tokenize.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index d578c9ad9..f1672c027 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -1,4 +1,4 @@ -/* +/* * Cppcheck - A tool for static C/C++ code analysis * Copyright (C) 2007-2011 Daniel Marjamäki and Cppcheck team. * From 85b1ea21cf5f312454de306fcbd62c0873092c46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Sat, 19 Feb 2011 09:56:17 +0100 Subject: [PATCH 02/27] Fixed #2590 (segmentation fault of cppcheck ( {}int )) --- lib/checkother.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/checkother.cpp b/lib/checkother.cpp index 233f562a8..07132a2d0 100644 --- a/lib/checkother.cpp +++ b/lib/checkother.cpp @@ -321,7 +321,7 @@ void CheckOther::checkSelfAssignment() std::set pod; for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) { - if (tok->isStandardType() && tok->next()->varId() && Token::Match(tok->tokAt(2), "[,);]")) + if (tok->isStandardType() && Token::Match(tok->tokAt(2), "[,);]") && tok->next()->varId()) pod.insert(tok->next()->varId()); } From f9b1505115136d0676f4c4e102ae9597b1a44ceb Mon Sep 17 00:00:00 2001 From: Robert Reif Date: Sat, 19 Feb 2011 13:40:02 -0500 Subject: [PATCH 03/27] fix Scope::findInNestedListRecursive to check all children --- lib/symboldatabase.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index 05a0aa0a5..6ae136386 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -1422,7 +1422,8 @@ Scope * Scope::findInNestedListRecursive(const std::string & name) for (it = nestedList.begin(); it != nestedList.end(); ++it) { Scope *child = (*it)->findInNestedListRecursive(name); - return child; + if (child) + return child; } return 0; } From 77fe9858e2094cfa4257c58def9c35b3e7dda72e Mon Sep 17 00:00:00 2001 From: Robert Reif Date: Sat, 19 Feb 2011 14:18:37 -0500 Subject: [PATCH 04/27] fix #2587 (Spurious warning about struct hiding typedef) --- lib/tokenize.cpp | 32 +++++++++++++++++++++----------- test/testsimplifytokens.cpp | 18 ++++++++++++++++++ 2 files changed, 39 insertions(+), 11 deletions(-) diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index f1672c027..dca75a1ad 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -837,19 +837,29 @@ static Token *splitDefinitionFromTypedef(Token *tok) tok1->insertToken(";"); tok1 = tok1->next(); - tok1->insertToken("typedef"); - tok1 = tok1->next(); - Token * tok3 = tok1; - if (isConst) + + if (tok1->next()->str() == ";" && tok1 && tok1->previous()->str() == "}") { - tok1->insertToken("const"); - tok1 = tok1->next(); + tok->deleteThis(); + tok1->deleteThis(); + return NULL; + } + else + { + tok1->insertToken("typedef"); + tok1 = tok1->next(); + Token * tok3 = tok1; + if (isConst) + { + tok1->insertToken("const"); + tok1 = tok1->next(); + } + tok1->insertToken(tok->next()->str()); // struct, union or enum + tok1 = tok1->next(); + tok1->insertToken(name.c_str()); + tok->deleteThis(); + tok = tok3; } - tok1->insertToken(tok->next()->str()); // struct, union or enum - tok1 = tok1->next(); - tok1->insertToken(name.c_str()); - tok->deleteThis(); - tok = tok3; return tok; } diff --git a/test/testsimplifytokens.cpp b/test/testsimplifytokens.cpp index a4c507cd4..85af6da62 100644 --- a/test/testsimplifytokens.cpp +++ b/test/testsimplifytokens.cpp @@ -237,6 +237,7 @@ private: TEST_CASE(simplifyTypedef77); // ticket #2554 TEST_CASE(simplifyTypedef78); // ticket #2568 TEST_CASE(simplifyTypedef79); // ticket #2348 + TEST_CASE(simplifyTypedef80); // ticket #2587 TEST_CASE(simplifyTypedefFunction1); TEST_CASE(simplifyTypedefFunction2); // ticket #1685 @@ -4876,6 +4877,23 @@ private: ASSERT_EQUALS(expected, sizeof_(code)); } + void simplifyTypedef80() // ticket #2587 + { + const char code[] = "typedef struct s { };\n" + "void f() {\n" + " sizeof(struct s);\n" + "};\n"; + const std::string expected = "struct s { } ; " + "void f ( ) { " + "sizeof ( struct s ) ; " + "} ;"; + ASSERT_EQUALS(expected, sizeof_(code)); + + // Check for output.. + checkSimplifyTypedef(code); + ASSERT_EQUALS("", errout.str()); + } + void simplifyTypedefFunction1() { { From caca6e94e6e3d78253b2b5b4bb7bcdca2b413434 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Sat, 19 Feb 2011 20:19:46 +0100 Subject: [PATCH 05/27] Fixed #2231 (uninitialized variable: undetected when initialization in for loop) --- lib/executionpath.cpp | 34 ++++++++++++++++++++++++++++++++++ test/testnullpointer.cpp | 15 +++++++++++++++ test/testuninitvar.cpp | 15 +++++++++++++++ 3 files changed, 64 insertions(+) diff --git a/lib/executionpath.cpp b/lib/executionpath.cpp index 7e8b6c4c7..774b9c28d 100644 --- a/lib/executionpath.cpp +++ b/lib/executionpath.cpp @@ -275,6 +275,40 @@ void ExecutionPath::checkScope(const Token *tok, std::list &che ++it; } + // #2231 - loop body only contains a conditional initialization.. + if (Token::simpleMatch(tok2->next(), "if (")) + { + // Start { for the if block + const Token *tok3 = tok2->tokAt(2)->link(); + if (Token::simpleMatch(tok3,") {")) + { + tok3 = tok3->next(); + + // End } for the if block + const Token *tok4 = tok3->link(); + if (Token::Match(tok3, "{ %var% =") && + Token::simpleMatch(tok4, "} }") && + Token::simpleMatch(tok4->tokAt(-2), "break ;")) + { + // Is there a assignment and then a break? + const Token *t = Token::findmatch(tok3, ";"); + if (t && t->tokAt(3) == tok4) + { + for (std::list::iterator it = checks.begin(); it != checks.end(); ++it) + { + if ((*it)->varId == tok3->next()->varId()) + { + (*it)->numberOfIf++; + break; + } + } + tok = tok2->link(); + continue; + } + } + } + } + // parse loop bodies check->parseLoopBody(tok2->next(), checks); } diff --git a/test/testnullpointer.cpp b/test/testnullpointer.cpp index 03a7d0e1b..82f108fac 100644 --- a/test/testnullpointer.cpp +++ b/test/testnullpointer.cpp @@ -718,6 +718,21 @@ private: "}\n"); TODO_ASSERT_EQUALS("error", "", errout.str()); + + // #2231 - error if assignment in loop is not used + check("void f() {\n" + " char *p = 0;\n" + "\n" + " for (int x = 0; x < 3; ++x) {\n" + " if (y[x] == 0) {\n" + " p = malloc(10);\n" + " break;\n" + " }\n" + " }\n" + "\n" + " *p = 0;\n" + "}"); + ASSERT_EQUALS("[test.cpp:11]: (error) Possible null pointer dereference: p\n", errout.str()); } void nullpointer7() diff --git a/test/testuninitvar.cpp b/test/testuninitvar.cpp index 1aee1c480..fbd29681d 100644 --- a/test/testuninitvar.cpp +++ b/test/testuninitvar.cpp @@ -801,6 +801,21 @@ private: "}\n"); TODO_ASSERT_EQUALS("[test.cpp:4]: (error) Uninitialized variable: pItem\n", "", errout.str()); + + // #2231 - conditional initialization in loop.. + checkUninitVar("int foo(char *a) {\n" + " int x;\n" + "\n" + " for (int i = 0; i < 10; ++i) {\n" + " if (a[i] == 'x') {\n" + " x = i;\n" + " break;\n" + " }\n" + " }\n" + "\n" + " return x;\n" + "}"); + ASSERT_EQUALS("[test.cpp:11]: (error) Uninitialized variable: x\n", errout.str()); } // switch.. From e6eb160395b3353c7ea6ce0ff5a7232914bb0dea Mon Sep 17 00:00:00 2001 From: Robert Reif Date: Sat, 19 Feb 2011 14:38:00 -0500 Subject: [PATCH 06/27] fix [B#2589 (segmentation fault of cppcheck (struct B : A)) --- lib/checkbufferoverrun.cpp | 2 +- lib/symboldatabase.cpp | 11 +++++++++++ test/testclass.cpp | 9 +++++++++ 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/lib/checkbufferoverrun.cpp b/lib/checkbufferoverrun.cpp index 85963c36e..4cda0ce51 100644 --- a/lib/checkbufferoverrun.cpp +++ b/lib/checkbufferoverrun.cpp @@ -1405,7 +1405,7 @@ void CheckBufferOverrun::checkStructVariable() const std::string &structname = tok->next()->str(); const Token *tok2 = tok; - while (tok2->str() != "{") + while (tok2 && tok2->str() != "{") tok2 = tok2->next(); // Found a struct declaration. Search for arrays.. diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index 6ae136386..f460b4adb 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -57,6 +57,13 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti // goto initial '{' tok2 = initBaseInfo(new_scope, tok); + + // make sure we have valid code + if (!tok2) + { + delete new_scope; + break; + } } new_scope->classStart = tok2; @@ -872,6 +879,10 @@ const Token *SymbolDatabase::initBaseInfo(Scope *scope, const Token *tok) tok2 = tok2->next(); + // check for invalid code + if (!tok2->next()) + return NULL; + if (tok2->str() == "public") { base.access = Public; diff --git a/test/testclass.cpp b/test/testclass.cpp index 9ea23b8fb..265a58375 100644 --- a/test/testclass.cpp +++ b/test/testclass.cpp @@ -192,6 +192,7 @@ private: TEST_CASE(symboldatabase11); // ticket #2539 TEST_CASE(symboldatabase12); // ticket #2547 TEST_CASE(symboldatabase13); // ticket #2577 + TEST_CASE(symboldatabase14); // ticket #2589 } // Check the operator Equal @@ -5550,6 +5551,14 @@ private: ASSERT_EQUALS("", errout.str()); } + void symboldatabase14() + { + // ticket #2589 - segmentation fault + checkConst("struct B : A\n"); + + ASSERT_EQUALS("", errout.str()); + } + }; REGISTER_TEST(TestClass) From e7ef1b3627198ef27ca26917925ef10a9f6eb052 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Sat, 19 Feb 2011 21:01:38 +0100 Subject: [PATCH 07/27] Null pointer: fixed false negative when dereferencing struct and then checking if it's null. Ticket: #2379 --- lib/checknullpointer.cpp | 13 ++++++++++++- test/testnullpointer.cpp | 20 +++++++++++++++++--- 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/lib/checknullpointer.cpp b/lib/checknullpointer.cpp index 698476b12..5f31ff60e 100644 --- a/lib/checknullpointer.cpp +++ b/lib/checknullpointer.cpp @@ -350,8 +350,19 @@ void CheckNullPointer::nullPointerStructByDeRefAndChec() continue; } + /** + * @todo There are lots of false negatives here. A dereference + * is only investigated if a few specific conditions are met. + */ + // dereference in assignment - if (Token::Match(tok1, "[{};] %var% = %var% . %var%")) + if (Token::Match(tok1, "[;{}] %var% . %var%")) + { + tok1 = tok1->next(); + } + + // dereference in assignment + else if (Token::Match(tok1, "[{};] %var% = %var% . %var%")) { if (std::string(tok1->strAt(1)) == tok1->strAt(3)) continue; diff --git a/test/testnullpointer.cpp b/test/testnullpointer.cpp index 82f108fac..e106577c2 100644 --- a/test/testnullpointer.cpp +++ b/test/testnullpointer.cpp @@ -193,13 +193,27 @@ private: "}\n"); ASSERT_EQUALS("[test.cpp:3]: (error) Possible null pointer dereference: abc - otherwise it is redundant to check if abc is null at line 4\n", errout.str()); - check("void foo(struct ABC *abc)\n" - "{\n" + check("void foo(struct ABC *abc) {\n" " bar(abc->a);\n" " if (!abc)\n" " ;\n" "}\n"); - ASSERT_EQUALS("[test.cpp:3]: (error) Possible null pointer dereference: abc - otherwise it is redundant to check if abc is null at line 4\n", errout.str()); + ASSERT_EQUALS("[test.cpp:2]: (error) Possible null pointer dereference: abc - otherwise it is redundant to check if abc is null at line 3\n", errout.str()); + + check("void foo(ABC *abc) {\n" + " abc->do_something();\n" + " if (abc)\n" + " ;\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:2]: (error) Possible null pointer dereference: abc - otherwise it is redundant to check if abc is null at line 3\n", errout.str()); + + // TODO: False negative if member of member is dereferenced + check("void foo(ABC *abc) {\n" + " abc->next->a = 0;\n" + " if (abc->next)\n" + " ;\n" + "}\n"); + TODO_ASSERT_EQUALS("[test.cpp:2]: (error) Possible null pointer dereference: abc - otherwise it is redundant to check if abc is null at line 3\n", "", errout.str()); // ok dereferencing in a condition check("void foo(struct ABC *abc)\n" From 29d05cf5f298b4c7480c4b1366a089853fc84a49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Sat, 19 Feb 2011 21:10:31 +0100 Subject: [PATCH 08/27] Null pointers: Fixed false negative for such code: 'abc->a = 0; if (abc && ..'. Ticket: #2379 --- lib/checknullpointer.cpp | 4 ++-- test/testnullpointer.cpp | 7 +++++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/lib/checknullpointer.cpp b/lib/checknullpointer.cpp index 5f31ff60e..e4173bd84 100644 --- a/lib/checknullpointer.cpp +++ b/lib/checknullpointer.cpp @@ -444,8 +444,8 @@ void CheckNullPointer::nullPointerStructByDeRefAndChec() break; // Check if pointer is null. - // TODO: false negatives for something like: "if (p &&.."? - else if (Token::Match(tok2, "if ( !| %varid% )", varid1)) + // TODO: false negatives for "if (!p || .." + else if (Token::Match(tok2, "if ( !| %varid% )|&&", varid1)) { // Is this variable a pointer? if (isPointer(varid1)) diff --git a/test/testnullpointer.cpp b/test/testnullpointer.cpp index e106577c2..f6e124fa9 100644 --- a/test/testnullpointer.cpp +++ b/test/testnullpointer.cpp @@ -215,6 +215,13 @@ private: "}\n"); TODO_ASSERT_EQUALS("[test.cpp:2]: (error) Possible null pointer dereference: abc - otherwise it is redundant to check if abc is null at line 3\n", "", errout.str()); + check("void foo(ABC *abc) {\n" + " abc->a = 0;\n" + " if (abc && abc->b == 0)\n" + " ;\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:2]: (error) Possible null pointer dereference: abc - otherwise it is redundant to check if abc is null at line 3\n", errout.str()); + // ok dereferencing in a condition check("void foo(struct ABC *abc)\n" "{\n" From 5f0206725bd1b35f0b9a3a40c44498af2c6bb9b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Sat, 19 Feb 2011 21:28:18 +0100 Subject: [PATCH 09/27] Null pointers: Fixed false negative for such code 'if (p && *p==0) {} *p = 0;'. Ticket: #2379 --- lib/checknullpointer.cpp | 8 ++++---- test/testnullpointer.cpp | 7 +++++++ 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/lib/checknullpointer.cpp b/lib/checknullpointer.cpp index e4173bd84..4b4ca89b5 100644 --- a/lib/checknullpointer.cpp +++ b/lib/checknullpointer.cpp @@ -574,13 +574,13 @@ void CheckNullPointer::nullPointerByCheckAndDeRef() // vartok : token for the variable const Token *vartok = 0; - if (Token::Match(tok, "if ( ! %var% ) {")) + if (Token::Match(tok, "if ( ! %var% )|&&")) vartok = tok->tokAt(3); - else if (Token::Match(tok, "if ( NULL|0 == %var% ) {")) + else if (Token::Match(tok, "if ( NULL|0 == %var% )|&&")) vartok = tok->tokAt(4); - else if (Token::Match(tok, "if ( %var% == NULL|0 ) {")) + else if (Token::Match(tok, "if ( %var% == NULL|0 )|&&")) vartok = tok->tokAt(2); - else if (Token::Match(tok, "if|while ( %var% ) {") && + else if (Token::Match(tok, "if|while ( %var% )|&&") && !Token::simpleMatch(tok->tokAt(4)->link(), "} else")) vartok = tok->tokAt(2); else diff --git a/test/testnullpointer.cpp b/test/testnullpointer.cpp index f6e124fa9..c96ecec51 100644 --- a/test/testnullpointer.cpp +++ b/test/testnullpointer.cpp @@ -823,6 +823,13 @@ private: "}\n"); ASSERT_EQUALS("[test.cpp:4]: (error) Possible null pointer dereference: p\n", errout.str()); + check("void foo(char *p) {\n" + " if (p && *p == 0) {\n" + " }\n" + " printf(\"%c\", *p);\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:4]: (error) Possible null pointer dereference: p\n", errout.str()); + check("void foo(abc *p) {\n" " if (!p) {\n" " }\n" From 98ab34b2b5e92fe47cfc4d279fcc14186ef9e05a Mon Sep 17 00:00:00 2001 From: Greg Hewgill Date: Sun, 20 Feb 2011 11:36:03 +1300 Subject: [PATCH 10/27] Support cppcheck-suppression in C style comments --- lib/preprocessor.cpp | 248 +++++++++++++++++++++----------------- test/testsuppressions.cpp | 29 +++++ 2 files changed, 166 insertions(+), 111 deletions(-) diff --git a/lib/preprocessor.cpp b/lib/preprocessor.cpp index fe35a7f81..8050770bb 100644 --- a/lib/preprocessor.cpp +++ b/lib/preprocessor.cpp @@ -338,20 +338,32 @@ std::string Preprocessor::removeComments(const std::string &str, const std::stri continue; } - // We have finished a line that didn't contain any comment - // (the '\n' is swallowed when a // comment is detected) - if ((ch == '\n' || str.compare(i,2,"//")==0) && !suppressionIDs.empty()) + // First skip over any whitespace that may be present + if (std::isspace(ch)) { - // Add the suppressions. - for (size_t j(0); j < suppressionIDs.size(); ++j) + if (ch == ' ' && previous == ' ') { - const std::string errmsg(settings->nomsg.addSuppression(suppressionIDs[j], filename, lineno)); - if (!errmsg.empty()) + // Skip double white space + } + else + { + code << char(ch); + previous = ch; + } + + // if there has been sequences, add extra newlines.. + if (ch == '\n') + { + ++lineno; + if (newlines > 0) { - writeError(filename, lineno, _errorLogger, "cppcheckError", errmsg); + code << std::string(newlines, '\n'); + newlines = 0; + previous = '\n'; } } - suppressionIDs.clear(); + + continue; } // Remove comments.. @@ -382,6 +394,7 @@ std::string Preprocessor::removeComments(const std::string &str, const std::stri } else if (str.compare(i, 2, "/*", 0, 2) == 0) { + size_t commentStart = i + 2; unsigned char chPrev = 0; ++i; while (i < str.length() && (chPrev != '*' || ch != '/')) @@ -395,126 +408,139 @@ std::string Preprocessor::removeComments(const std::string &str, const std::stri ++lineno; } } - } - // String or char constants.. - else if (ch == '\"' || ch == '\'') - { - code << char(ch); - char chNext; - do + if (settings && settings->_inlineSuppressions) { - ++i; - chNext = str[i]; - if (chNext == '\\') + std::string comment(str, commentStart, i - commentStart); + std::istringstream iss(comment); + std::string word; + iss >> word; + if (word == "cppcheck-suppress") + { + iss >> word; + if (iss) + suppressionIDs.push_back(word); + } + } + } + else + { + // Not whitespace and not a comment. Must be code here! + // Add any pending inline suppressions that have accumulated. + if (!suppressionIDs.empty()) + { + if (settings != NULL) + { + // Add the suppressions. + for (size_t j(0); j < suppressionIDs.size(); ++j) + { + const std::string errmsg(settings->nomsg.addSuppression(suppressionIDs[j], filename, lineno)); + if (!errmsg.empty()) + { + writeError(filename, lineno, _errorLogger, "cppcheckError", errmsg); + } + } + } + suppressionIDs.clear(); + } + + // String or char constants.. + if (ch == '\"' || ch == '\'') + { + code << char(ch); + char chNext; + do { ++i; - char chSeq = str[i]; - if (chSeq == '\n') - ++newlines; + chNext = str[i]; + if (chNext == '\\') + { + ++i; + char chSeq = str[i]; + if (chSeq == '\n') + ++newlines; + else + { + code << chNext; + code << chSeq; + previous = static_cast(chSeq); + } + } else { code << chNext; - code << chSeq; - previous = static_cast(chSeq); + previous = static_cast(chNext); } } + while (i < str.length() && chNext != ch && chNext != '\n'); + } + + // Rawstring.. + else if (str.compare(i,2,"R\"")==0) + { + std::string delim; + for (std::string::size_type i2 = i+2; i2 < str.length(); ++i2) + { + if (i2 > 16 || + std::isspace(str[i2]) || + std::iscntrl(str[i2]) || + str[i2] == ')' || + str[i2] == '\\') + { + delim = " "; + break; + } + else if (str[i2] == '(') + break; + + delim += str[i2]; + } + const std::string::size_type endpos = str.find(")" + delim + "\"", i); + if (delim != " " && endpos != std::string::npos) + { + unsigned int rawstringnewlines = 0; + code << '\"'; + for (std::string::size_type p = i + 3 + delim.size(); p < endpos; ++p) + { + if (str[p] == '\n') + { + rawstringnewlines++; + code << "\\n"; + } + else if (std::iscntrl((unsigned char)str[p]) || + std::isspace((unsigned char)str[p])) + { + code << " "; + } + else if (str[p] == '\\') + { + code << "\\"; + } + else if (str[p] == '\"' || str[p] == '\'') + { + code << "\\" << (char)str[p]; + } + else + { + code << (char)str[p]; + } + } + code << "\""; + if (rawstringnewlines > 0) + code << std::string(rawstringnewlines, '\n'); + i = endpos + delim.size() + 2; + } else { - code << chNext; - previous = static_cast(chNext); + code << "R"; + previous = 'R'; } } - while (i < str.length() && chNext != ch && chNext != '\n'); - } - - // Rawstring.. - else if (str.compare(i,2,"R\"")==0) - { - std::string delim; - for (std::string::size_type i2 = i+2; i2 < str.length(); ++i2) - { - if (i2 > 16 || - std::isspace(str[i2]) || - std::iscntrl(str[i2]) || - str[i2] == ')' || - str[i2] == '\\') - { - delim = " "; - break; - } - else if (str[i2] == '(') - break; - - delim += str[i2]; - } - const std::string::size_type endpos = str.find(")" + delim + "\"", i); - if (delim != " " && endpos != std::string::npos) - { - unsigned int rawstringnewlines = 0; - code << '\"'; - for (std::string::size_type p = i + 3 + delim.size(); p < endpos; ++p) - { - if (str[p] == '\n') - { - rawstringnewlines++; - code << "\\n"; - } - else if (std::iscntrl((unsigned char)str[p]) || - std::isspace((unsigned char)str[p])) - { - code << " "; - } - else if (str[p] == '\\') - { - code << "\\"; - } - else if (str[p] == '\"' || str[p] == '\'') - { - code << "\\" << (char)str[p]; - } - else - { - code << (char)str[p]; - } - } - code << "\""; - if (rawstringnewlines > 0) - code << std::string(rawstringnewlines, '\n'); - i = endpos + delim.size() + 2; - } - else - { - code << "R"; - previous = 'R'; - } - } - - // Just some code.. - else - { - if (ch == ' ' && previous == ' ') - { - // Skip double white space - } else { code << char(ch); previous = ch; } - - - // if there has been sequences, add extra newlines.. - if (ch == '\n') - { - ++lineno; - if (newlines > 0) - { - code << std::string(newlines, '\n'); - newlines = 0; - previous = '\n'; - } - } } } diff --git a/test/testsuppressions.cpp b/test/testsuppressions.cpp index df6ac2627..e26a7042d 100644 --- a/test/testsuppressions.cpp +++ b/test/testsuppressions.cpp @@ -172,6 +172,35 @@ private: ""); ASSERT_EQUALS("", errout.str()); + // suppress uninitvar inline + (this->*check)("void f() {\n" + " int a;\n" + " // cppcheck-suppress uninitvar\n" + "\n" + " a++;\n" + "}\n", + ""); + ASSERT_EQUALS("", errout.str()); + + // suppress uninitvar inline + (this->*check)("void f() {\n" + " int a;\n" + " /* cppcheck-suppress uninitvar */\n" + " a++;\n" + "}\n", + ""); + ASSERT_EQUALS("", errout.str()); + + // suppress uninitvar inline + (this->*check)("void f() {\n" + " int a;\n" + " /* cppcheck-suppress uninitvar */\n" + "\n" + " a++;\n" + "}\n", + ""); + ASSERT_EQUALS("", errout.str()); + // suppress uninitvar inline, without error present (this->*check)("void f() {\n" " int a;\n" From fef1142997de7eacbade878ed67a7bed2237da53 Mon Sep 17 00:00:00 2001 From: Robert Reif Date: Sat, 19 Feb 2011 20:02:16 -0500 Subject: [PATCH 11/27] fix #2592 (False positive: 'operator=' should return reference to self) --- lib/checkclass.cpp | 4 +++- test/testclass.cpp | 21 +++++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/lib/checkclass.cpp b/lib/checkclass.cpp index ddbef4288..0a90fbcf0 100644 --- a/lib/checkclass.cpp +++ b/lib/checkclass.cpp @@ -872,7 +872,9 @@ void CheckClass::checkReturnPtrThis(const Scope *scope, const Function *func, co // check of *this is returned else if (!(Token::Match(tok->tokAt(1), "(| * this ;|=") || Token::Match(tok->tokAt(1), "(| * this +=") || - Token::simpleMatch(tok->tokAt(1), "operator= ("))) + Token::simpleMatch(tok->tokAt(1), "operator= (") || + (Token::Match(tok->tokAt(1), "%type% :: operator= (") && + tok->next()->str() == scope->className))) operatorEqRetRefThisError(func->token); } } diff --git a/test/testclass.cpp b/test/testclass.cpp index 265a58375..f8b2515f4 100644 --- a/test/testclass.cpp +++ b/test/testclass.cpp @@ -113,6 +113,7 @@ private: TEST_CASE(operatorEqToSelf6); // ticket # 1550 TEST_CASE(operatorEqToSelf7); TEST_CASE(operatorEqToSelf8); // ticket #2179 + TEST_CASE(operatorEqToSelf9); // ticket #2592 TEST_CASE(memsetOnStruct); TEST_CASE(memsetVector); TEST_CASE(memsetOnClass); @@ -1299,6 +1300,26 @@ private: ASSERT_EQUALS("", errout.str()); } + void operatorEqToSelf9() + { + checkOpertorEqToSelf( + "class Foo\n" + "{\n" + "public:\n" + " Foo& operator=(Foo* pOther);\n" + " Foo& operator=(Foo& other);\n" + "};\n" + "Foo& Foo::operator=(Foo* pOther)\n" + "{\n" + " return *this;\n" + "}\n" + "Foo& Foo::operator=(Foo& other)\n" + "{\n" + " return Foo::operator=(&other);\n" + "}\n"); + ASSERT_EQUALS("", errout.str()); + } + // Check that base classes have virtual destructors void checkVirtualDestructor(const char code[]) { From 7dd8a3283a0d9002b62a5f3cf28e99fe8270afc0 Mon Sep 17 00:00:00 2001 From: Robert Reif Date: Sat, 19 Feb 2011 20:09:07 -0500 Subject: [PATCH 12/27] fix comment in CheckClass::initializeVarList --- lib/checkclass.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/checkclass.cpp b/lib/checkclass.cpp index 0a90fbcf0..5fdd341a7 100644 --- a/lib/checkclass.cpp +++ b/lib/checkclass.cpp @@ -869,7 +869,7 @@ void CheckClass::checkReturnPtrThis(const Scope *scope, const Function *func, co } } - // check of *this is returned + // check if *this is returned else if (!(Token::Match(tok->tokAt(1), "(| * this ;|=") || Token::Match(tok->tokAt(1), "(| * this +=") || Token::simpleMatch(tok->tokAt(1), "operator= (") || From 46f4e46d30bd0c3e74f4de26318c4aa458a4ca20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Sun, 20 Feb 2011 12:17:05 +0100 Subject: [PATCH 13/27] Tokenizer::simplifyTemplates: Better handling for multi-token template arguments such as 'Foo' --- lib/tokenize.cpp | 101 +++++++++++++++++++++++++----------- test/testsimplifytokens.cpp | 14 +++++ 2 files changed, 85 insertions(+), 30 deletions(-) diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index dca75a1ad..9b586e188 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -2467,21 +2467,31 @@ void Tokenizer::labels() * is the token pointing at a template parameters block * < int , 3 > => yes * \param tok start token that must point at "<" - * \return true if the tokens look like template parameters + * \return number of parameters (invalid parameters => 0) */ -static bool templateParameters(const Token *tok) +static unsigned int templateParameters(const Token *tok) { + unsigned int numberOfParameters = 0; + if (!tok) - return false; + return 0; if (tok->str() != "<") - return false; + return 0; tok = tok->next(); while (tok) { + ++numberOfParameters; + + // skip std:: + while (Token::Match(tok, "%var% ::")) + tok = tok->tokAt(2); + if (!tok) + return 0; + // num/type .. if (!tok->isNumber() && !tok->isName()) - return false; + return 0; tok = tok->next(); // optional "*" @@ -2490,12 +2500,12 @@ static bool templateParameters(const Token *tok) // ,/> if (tok->str() == ">") - return true; + return numberOfParameters; if (tok->str() != ",") break; tok = tok->next(); } - return false; + return 0; } @@ -2778,6 +2788,33 @@ void Tokenizer::simplifyTemplatesUseDefaultArgumentValues(const std::list" + * @return match => true + */ +static bool simplifyTemplatesInstantiateMatch(const Token *instance, const std::string &name, unsigned int numberOfArguments, const char patternAfter[]) +{ + if (!Token::simpleMatch(instance, (name + " <").c_str())) + return false; + + if (numberOfArguments != templateParameters(instance->next())) + return false; + + if (patternAfter) + { + const Token *tok = Token::findmatch(instance, ">"); + if (!tok || !Token::Match(tok->next(), patternAfter)) + return false; + } + + // nothing mismatching was found.. + return true; +} + void Tokenizer::simplifyTemplatesInstantiate(const Token *tok, std::list &used, std::set &expandedtemplates) @@ -2836,16 +2873,6 @@ void Tokenizer::simplifyTemplatesInstantiate(const Token *tok, const bool isfunc(tok->strAt(namepos + 1) == "("); // locate template usage.. - - std::string s(name + " <"); - for (unsigned int i = 0; i < type.size(); ++i) - { - if (i > 0) - s += ","; - s += " %any% "; - } - const std::string pattern(s + "> "); - std::string::size_type sz1 = used.size(); unsigned int recursiveCount = 0; @@ -2865,17 +2892,16 @@ void Tokenizer::simplifyTemplatesInstantiate(const Token *tok, } Token * const tok2 = *iter2; - if (tok2->str() != name) continue; if (Token::Match(tok2->previous(), "[;{}=]") && - !Token::Match(tok2, (pattern + (isfunc ? "(" : "*| %var%")).c_str())) + !simplifyTemplatesInstantiateMatch(*iter2, name, type.size(), isfunc ? "(" : "*| %var%")) continue; // New type.. - std::vector types2; - s = ""; + std::vector types2; + std::string s; std::string s1(name + " < "); for (const Token *tok3 = tok2->tokAt(2); tok3 && tok3->str() != ">"; tok3 = tok3->next()) { @@ -2886,8 +2912,8 @@ void Tokenizer::simplifyTemplatesInstantiate(const Token *tok, } s1 += tok3->str(); s1 += " "; - if (tok3->str() != ",") - types2.push_back(*tok3); + if (Token::Match(tok3->previous(), "[<,]")) + types2.push_back(tok3); // add additional type information if (tok3->isUnsigned()) s += "unsigned"; @@ -2949,7 +2975,9 @@ void Tokenizer::simplifyTemplatesInstantiate(const Token *tok, } // member function implemented outside class definition - else if (_indentlevel == 0 && _parlevel == 0 && Token::Match(tok3, (pattern + " :: ~| %var% (").c_str())) + else if (_indentlevel == 0 && + _parlevel == 0 && + simplifyTemplatesInstantiateMatch(tok3, name, type.size(), ":: ~| %var% (")) { addtoken(name2.c_str(), tok3->linenr(), tok3->fileIndex()); while (tok3->str() != "::") @@ -2997,7 +3025,12 @@ void Tokenizer::simplifyTemplatesInstantiate(const Token *tok, // replace type with given type.. if (itype < type.size()) { - addtoken(&types2[itype], tok3->linenr(), tok3->fileIndex()); + for (const Token *typetok = types2[itype]; + typetok && !Token::Match(typetok, "[,>]"); + typetok = typetok->next()) + { + addtoken(typetok, tok3->linenr(), tok3->fileIndex()); + } continue; } } @@ -3065,18 +3098,26 @@ void Tokenizer::simplifyTemplatesInstantiate(const Token *tok, bool match = true; Token * tok5 = tok4->tokAt(2); unsigned int count = 0; + const Token *typetok = (!types2.empty()) ? types2[0] : 0; while (tok5->str() != ">") { if (tok5->str() != ",") { - if (tok5->isUnsigned() != types2[count].isUnsigned() || - tok5->isSigned() != types2[count].isSigned() || - tok5->isLong() != types2[count].isLong()) + if (!typetok || + tok5->isUnsigned() != typetok->isUnsigned() || + tok5->isSigned() != typetok->isSigned() || + tok5->isLong() != typetok->isLong()) { match = false; break; } - count++; + + typetok = typetok ? typetok->next() : 0; + } + else + { + ++count; + typetok = (count < types2.size()) ? types2[count] : 0; } tok5 = tok5->next(); } @@ -9190,7 +9231,7 @@ void Tokenizer::simplifyBorland() void Tokenizer::simplifyQtSignalsSlots() { Token *tok = _tokens; - while ((tok = const_cast(Token::findmatch(tok, "class %var% :")))) + while (NULL != (tok = const_cast(Token::findmatch(tok, "class %var% :")))) { if (tok->previous() && tok->previous()->str() == "enum") { diff --git a/test/testsimplifytokens.cpp b/test/testsimplifytokens.cpp index 85af6da62..9a3a36dc2 100644 --- a/test/testsimplifytokens.cpp +++ b/test/testsimplifytokens.cpp @@ -110,6 +110,7 @@ private: TEST_CASE(template19); TEST_CASE(template20); TEST_CASE(template21); + TEST_CASE(template22); TEST_CASE(template_unhandled); TEST_CASE(template_default_parameter); TEST_CASE(template_default_type); @@ -1985,6 +1986,19 @@ private: } } + void template22() + { + const char code[] = "template struct Fred { T a; };\n" + "Fred fred;"; + + const std::string expected("; " + "Fred fred ; " + "struct Fred { std :: string a ; }"); + + ASSERT_EQUALS(expected, sizeof_(code)); + } + + void template_unhandled() { // An unhandled template usage should be simplified.. From 1cfb18be08cbab24fa13f66b538968c5e33dcd66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Sun, 20 Feb 2011 12:22:01 +0100 Subject: [PATCH 14/27] astyle formatting --- lib/tokenize.cpp | 12 ++++++------ test/testsimplifytokens.cpp | 14 +++++++------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 9b586e188..edd51acfa 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -2482,7 +2482,7 @@ static unsigned int templateParameters(const Token *tok) while (tok) { ++numberOfParameters; - + // skip std:: while (Token::Match(tok, "%var% ::")) tok = tok->tokAt(2); @@ -2975,8 +2975,8 @@ void Tokenizer::simplifyTemplatesInstantiate(const Token *tok, } // member function implemented outside class definition - else if (_indentlevel == 0 && - _parlevel == 0 && + else if (_indentlevel == 0 && + _parlevel == 0 && simplifyTemplatesInstantiateMatch(tok3, name, type.size(), ":: ~| %var% (")) { addtoken(name2.c_str(), tok3->linenr(), tok3->fileIndex()); @@ -3025,8 +3025,8 @@ void Tokenizer::simplifyTemplatesInstantiate(const Token *tok, // replace type with given type.. if (itype < type.size()) { - for (const Token *typetok = types2[itype]; - typetok && !Token::Match(typetok, "[,>]"); + for (const Token *typetok = types2[itype]; + typetok && !Token::Match(typetok, "[,>]"); typetok = typetok->next()) { addtoken(typetok, tok3->linenr(), tok3->fileIndex()); @@ -3111,7 +3111,7 @@ void Tokenizer::simplifyTemplatesInstantiate(const Token *tok, match = false; break; } - + typetok = typetok ? typetok->next() : 0; } else diff --git a/test/testsimplifytokens.cpp b/test/testsimplifytokens.cpp index 9a3a36dc2..23f219819 100644 --- a/test/testsimplifytokens.cpp +++ b/test/testsimplifytokens.cpp @@ -1988,15 +1988,15 @@ private: void template22() { - const char code[] = "template struct Fred { T a; };\n" - "Fred fred;"; + const char code[] = "template struct Fred { T a; };\n" + "Fred fred;"; - const std::string expected("; " - "Fred fred ; " - "struct Fred { std :: string a ; }"); + const std::string expected("; " + "Fred fred ; " + "struct Fred { std :: string a ; }"); - ASSERT_EQUALS(expected, sizeof_(code)); - } + ASSERT_EQUALS(expected, sizeof_(code)); + } void template_unhandled() From 597aea9f15cf6bf151bec88496e97e00ad30a199 Mon Sep 17 00:00:00 2001 From: Robert Reif Date: Sun, 20 Feb 2011 08:25:42 -0500 Subject: [PATCH 15/27] save start of function '{' and start of variable declaration in symbol database so checks don't have to find them --- lib/symboldatabase.cpp | 24 ++++++++++++++++++++++-- lib/symboldatabase.h | 25 ++++++++++++++++++++----- 2 files changed, 42 insertions(+), 7 deletions(-) diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index f460b4adb..0eafe3ebb 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -220,7 +220,7 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti function.isConst = true; // pure virtual function - if (Token::Match(end, ") const| = %any% ;")) + if (Token::Match(end, ") const| = %any%")) function.isPure = true; // count the number of constructors @@ -248,6 +248,13 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti function.isInline = true; function.hasBody = true; + // find start of function '{' + while (end && end->str() != "{") + end = end->next(); + + // save start of function + function.start = end; + scope->functionList.push_back(function); const Token *tok2 = funcStart; @@ -768,6 +775,10 @@ void SymbolDatabase::addFunction(Scope **scope, const Token **tok, const Token * func->hasBody = true; func->token = *tok; func->arg = argStart; + const Token *start = argStart->link()->next(); + while (start && start->str() != "{") + start = start->next(); + func->start = start; } } else if (func->tokenDef->str() == (*tok)->str() && (*tok)->previous()->str() != "~") @@ -783,6 +794,10 @@ void SymbolDatabase::addFunction(Scope **scope, const Token **tok, const Token * func->hasBody = true; func->token = *tok; func->arg = argStart; + const Token *start = argStart->link()->next(); + while (start && start->str() != "{") + start = start->next(); + func->start = start; } } @@ -793,6 +808,10 @@ void SymbolDatabase::addFunction(Scope **scope, const Token **tok, const Token * func->hasBody = true; func->token = *tok; func->arg = argStart; + const Token *start = argStart->link()->next()->next()->link()->next(); + while (start && start->str() != "{") + start = start->next(); + func->start = start; } } } @@ -1153,6 +1172,7 @@ void Scope::getVariableList() // This is the start of a statement const Token *vartok = NULL; const Token *typetok = NULL; + const Token *typestart = tok; // Is it const..? bool isConst = false; @@ -1222,7 +1242,7 @@ void Scope::getVariableList() if (typetok) scope = check->findVariableType(this, typetok); - addVariable(vartok, varaccess, isMutable, isStatic, isConst, isClass, scope); + addVariable(vartok, typestart, varaccess, isMutable, isStatic, isConst, isClass, scope); } } } diff --git a/lib/symboldatabase.h b/lib/symboldatabase.h index 4e04f4d5a..b21417c51 100644 --- a/lib/symboldatabase.h +++ b/lib/symboldatabase.h @@ -73,10 +73,11 @@ class Variable } public: - Variable(const Token *name_, std::size_t index_, AccessControl access_, - bool mutable_, bool static_, bool const_, bool class_, - const Scope *type_) + Variable(const Token *name_, const Token *start_, std::size_t index_, + AccessControl access_, bool mutable_, bool static_, bool const_, + bool class_, const Scope *type_) : _name(name_), + _start(start_), _index(index_), _access(access_), _flags(0), @@ -97,6 +98,15 @@ public: return _name; } + /** + * Get type start token. + * @return type start token + */ + const Token *typeStartToken() const + { + return _start; + } + /** * Get name string. * @return name string @@ -200,6 +210,9 @@ private: /** @brief variable name token */ const Token *_name; + /** @brief variable type start token */ + const Token *_start; + /** @brief order declared */ std::size_t _index; @@ -223,6 +236,7 @@ public: argDef(NULL), token(NULL), arg(NULL), + start(NULL), access(Public), hasBody(false), isInline(false), @@ -245,6 +259,7 @@ public: const Token *argDef; // function argument start '(' in class definition const Token *token; // function name token in implementation const Token *arg; // function argument start '(' + const Token *start; // function start '{' AccessControl access; // public/protected/private bool hasBody; // has implementation bool isInline; // implementation in class definition @@ -317,9 +332,9 @@ public: */ Scope * findInNestedListRecursive(const std::string & name); - void addVariable(const Token *token_, AccessControl access_, bool mutable_, bool static_, bool const_, bool class_, const Scope *type_) + void addVariable(const Token *token_, const Token *start_, AccessControl access_, bool mutable_, bool static_, bool const_, bool class_, const Scope *type_) { - varlist.push_back(Variable(token_, varlist.size(), access_, mutable_, static_, const_, class_, type_)); + varlist.push_back(Variable(token_, start_, varlist.size(), access_, mutable_, static_, const_, class_, type_)); } /** @brief initialize varlist */ From 537ac0cb3484f89311427de8a1355754b890b563 Mon Sep 17 00:00:00 2001 From: Robert Reif Date: Sun, 20 Feb 2011 08:36:06 -0500 Subject: [PATCH 16/27] use func->start rather than searching for '{' in CheckClass::privateFunctions --- lib/checkclass.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/checkclass.cpp b/lib/checkclass.cpp index 5fdd341a7..4b9056083 100644 --- a/lib/checkclass.cpp +++ b/lib/checkclass.cpp @@ -640,9 +640,7 @@ void CheckClass::privateFunctions() // Check that all private functions are used.. for (func = scope->functionList.begin(); func != scope->functionList.end(); ++func) { - const Token *ftok = func->arg->link()->next(); - while (ftok->str() != "{") - ftok = ftok->next(); + const Token *ftok = func->start; const Token *etok = ftok->link(); for (; ftok != etok; ftok = ftok->next()) From 7894d86132d6d50976610c121d8625ece617c1ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Sun, 20 Feb 2011 14:38:49 +0100 Subject: [PATCH 17/27] Null pointers: Fixed false negative for such code: 'if (p && *p) {} else { *p=0; }'. Ticket: #2379 --- lib/checknullpointer.cpp | 5 ++--- test/testnullpointer.cpp | 6 ++++++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/lib/checknullpointer.cpp b/lib/checknullpointer.cpp index 4b4ca89b5..6241dceae 100644 --- a/lib/checknullpointer.cpp +++ b/lib/checknullpointer.cpp @@ -580,8 +580,7 @@ void CheckNullPointer::nullPointerByCheckAndDeRef() vartok = tok->tokAt(4); else if (Token::Match(tok, "if ( %var% == NULL|0 )|&&")) vartok = tok->tokAt(2); - else if (Token::Match(tok, "if|while ( %var% )|&&") && - !Token::simpleMatch(tok->tokAt(4)->link(), "} else")) + else if (Token::Match(tok, "if|while ( %var% )|&&")) vartok = tok->tokAt(2); else continue; @@ -601,7 +600,7 @@ void CheckNullPointer::nullPointerByCheckAndDeRef() // start token = inside the if-body const Token *tok1 = tok->next()->link()->tokAt(2); - if (Token::Match(tok, "if|while ( %var% )")) + if (Token::Match(tok, "if|while ( %var% )|&&")) { // pointer might be null null = false; diff --git a/test/testnullpointer.cpp b/test/testnullpointer.cpp index c96ecec51..96a59d282 100644 --- a/test/testnullpointer.cpp +++ b/test/testnullpointer.cpp @@ -830,6 +830,12 @@ private: "}\n"); ASSERT_EQUALS("[test.cpp:4]: (error) Possible null pointer dereference: p\n", errout.str()); + check("void foo(char *p) {\n" + " if (p && *p == 0) {\n" + " } else { *p = 0; }\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:3]: (error) Possible null pointer dereference: p\n", errout.str()); + check("void foo(abc *p) {\n" " if (!p) {\n" " }\n" From 63c003f92e712e077b9f5ca032f3561131d1a1e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Sun, 20 Feb 2011 18:18:27 +0100 Subject: [PATCH 18/27] Tokenizer: fixed so that 'p=&x; if(p)' is simplified to 'p=&x;if(&x)'. Ticket: #2596 --- lib/tokenize.cpp | 13 ++++++++++--- lib/tokenize.h | 2 +- test/testsimplifytokens.cpp | 6 +----- test/testtokenize.cpp | 11 +++++++++++ 4 files changed, 23 insertions(+), 9 deletions(-) diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index edd51acfa..5184e3efb 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -6308,7 +6308,7 @@ bool Tokenizer::simplifyKnownVariables() if (tok2->str() == tok2->strAt(2)) continue; - const bool pointeralias(tok2->tokAt(2)->isName() || tok2->tokAt(2)->str() == "&"); + const Token * const valueToken = tok2->tokAt(2); std::string value; unsigned int valueVarId = 0; @@ -6319,7 +6319,7 @@ bool Tokenizer::simplifyKnownVariables() if (!simplifyKnownVariablesGetData(varid, &tok2, &tok3, value, valueVarId, valueIsPointer, floatvars.find(tok2->varId()) != floatvars.end())) continue; - ret |= simplifyKnownVariablesSimplify(&tok2, tok3, varid, structname, value, valueVarId, valueIsPointer, pointeralias, indentlevel); + ret |= simplifyKnownVariablesSimplify(&tok2, tok3, varid, structname, value, valueVarId, valueIsPointer, valueToken, indentlevel); } } @@ -6411,8 +6411,10 @@ bool Tokenizer::simplifyKnownVariablesGetData(unsigned int varid, Token **_tok2, return true; } -bool Tokenizer::simplifyKnownVariablesSimplify(Token **tok2, Token *tok3, unsigned int varid, const std::string &structname, std::string &value, unsigned int valueVarId, bool valueIsPointer, bool pointeralias, int indentlevel) +bool Tokenizer::simplifyKnownVariablesSimplify(Token **tok2, Token *tok3, unsigned int varid, const std::string &structname, std::string &value, unsigned int valueVarId, bool valueIsPointer, const Token * const valueToken, int indentlevel) { + const bool pointeralias(valueToken->isName() || Token::Match(valueToken, "& %var% [")); + bool ret = false; Token* bailOutFromLoop = 0; @@ -6591,6 +6593,11 @@ bool Tokenizer::simplifyKnownVariablesSimplify(Token **tok2, Token *tok3, unsign tok3->deleteNext(); tok3->deleteNext(); } + if (Token::Match(valueToken, "& %var% ;")) + { + tok3->insertToken("&"); + tok3 = tok3->next(); + } tok3 = tok3->next(); tok3->str(value); tok3->varId(valueVarId); diff --git a/lib/tokenize.h b/lib/tokenize.h index cc076e120..d5faa0812 100644 --- a/lib/tokenize.h +++ b/lib/tokenize.h @@ -320,7 +320,7 @@ public: * utility function for simplifyKnownVariables. Perform simplification * of a given variable */ - bool simplifyKnownVariablesSimplify(Token **tok2, Token *tok3, unsigned int varid, const std::string &structname, std::string &value, unsigned int valueVarId, bool valueIsPointer, bool pointeralias, int indentlevel); + bool simplifyKnownVariablesSimplify(Token **tok2, Token *tok3, unsigned int varid, const std::string &structname, std::string &value, unsigned int valueVarId, bool valueIsPointer, const Token * const valueToken, int indentlevel); /** Replace a "goto" with the statements */ void simplifyGoto(); diff --git a/test/testsimplifytokens.cpp b/test/testsimplifytokens.cpp index 23f219819..58273fa4a 100644 --- a/test/testsimplifytokens.cpp +++ b/test/testsimplifytokens.cpp @@ -5799,11 +5799,7 @@ private: "}\n"; const char expected[] = "int f ( ) " "{" - " int i ;" - " int * p ;" - " p = & i ;" - " i = 5 ;" - " return 5 ; " + " ; return 5 ; " "}"; ASSERT_EQUALS(expected, tok(code)); } diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index 504e1c769..02177d4bf 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -127,6 +127,7 @@ private: TEST_CASE(simplifyKnownVariables38); // ticket #2399 - simplify conditions TEST_CASE(simplifyKnownVariables39); TEST_CASE(simplifyKnownVariables40); + TEST_CASE(simplifyKnownVariables41); // p=&x; if (p) .. TEST_CASE(simplifyKnownVariablesBailOutAssign); TEST_CASE(simplifyKnownVariablesBailOutFor1); TEST_CASE(simplifyKnownVariablesBailOutFor2); @@ -2020,6 +2021,16 @@ private: ASSERT_EQUALS("void f ( ) {\n;\nchar c2 ; c2 = { 'a' } ;\n}", tokenizeAndStringify(code, true)); } + void simplifyKnownVariables41() + { + const char code[] = "void f() {\n" + " int x = 0;\n" + " const int *p; p = &x;\n" + " if (p) { return 0; }\n" + "}"; + ASSERT_EQUALS("void f ( ) {\nint x ; x = 0 ;\nconst int * p ; p = & x ;\nif ( & x ) { return 0 ; }\n}", tokenizeAndStringify(code, true)); + } + void simplifyKnownVariablesBailOutAssign() { const char code[] = "int foo() {\n" From 7f67438d9902b6c527bdb085586c6d79c86151e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Sun, 20 Feb 2011 19:45:34 +0100 Subject: [PATCH 19/27] Null pointer: Added TODO test case. Ticket: #2379 --- test/testnullpointer.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/testnullpointer.cpp b/test/testnullpointer.cpp index 96a59d282..635973e0c 100644 --- a/test/testnullpointer.cpp +++ b/test/testnullpointer.cpp @@ -207,6 +207,14 @@ private: "}\n"); ASSERT_EQUALS("[test.cpp:2]: (error) Possible null pointer dereference: abc - otherwise it is redundant to check if abc is null at line 3\n", errout.str()); + check("void foo(ABC *abc) {\n" + " if (abc->a == 3) {\n" + " return;\n" + " }\n" + " if (abc) {}\n" + "}"); + TODO_ASSERT_EQUALS("[test.cpp:2]: (error) Possible null pointer dereference: abc - otherwise it is redundant to check if abc is null at line 5\n", "", errout.str()); + // TODO: False negative if member of member is dereferenced check("void foo(ABC *abc) {\n" " abc->next->a = 0;\n" From 5dea79a07d7b77d5e60edbb3baa648c5dc7e0423 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Sun, 20 Feb 2011 19:56:13 +0100 Subject: [PATCH 20/27] cppcheckError: Rephrazed the error message. The 'internal error' sounds like something dangerous happens that needs to be fixed. So I think 'analysis failed' is better. If the code has a syntax error then 'analysis failed' is entirely ok. --- lib/tokenize.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 5184e3efb..868184a60 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -8136,7 +8136,7 @@ void Tokenizer::cppcheckError(const Token *tok) const const ErrorLogger::ErrorMessage errmsg(locationList, Severity::error, - "### Internal error in Cppcheck. Please report it.", + "Analysis failed. If the code is valid then please report this failure.", "cppcheckError"); if (_errorLogger) From f6e6fa685e6bdefe839869d1bbf7320aa1034eab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Sun, 20 Feb 2011 20:11:51 +0100 Subject: [PATCH 21/27] Preprocessor: Added TODO test case for #2563 --- test/testpreprocessor.cpp | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/test/testpreprocessor.cpp b/test/testpreprocessor.cpp index 7f032b3e6..b3ca40855 100644 --- a/test/testpreprocessor.cpp +++ b/test/testpreprocessor.cpp @@ -119,6 +119,7 @@ private: TEST_CASE(if_cond9); TEST_CASE(if_cond10); TEST_CASE(if_cond11); + TEST_CASE(if_cond12); TEST_CASE(if_or_1); TEST_CASE(if_or_2); @@ -1340,6 +1341,22 @@ private: ASSERT_EQUALS("", errout.str()); } + void if_cond12() + { + errout.str(""); + const char filedata[] = "#define A (1)\n" + "#if A == 1\n" + ";\n" + "#endif\n"; + std::istringstream istr(filedata); + std::map actual; + Settings settings; + Preprocessor preprocessor(&settings, this); + preprocessor.preprocess(istr, actual, "file.c"); + ASSERT_EQUALS("", errout.str()); + TODO_ASSERT_EQUALS("\n\n;\n\n", "\n\n\n\n", actual[""]); + } + void if_or_1() From c3fba356c095a0a28350654aa51423b35339b1af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Sun, 20 Feb 2011 20:57:28 +0100 Subject: [PATCH 22/27] Fixed #2563 (#if equality testing does not ignore parentheses) --- lib/preprocessor.cpp | 28 +++++++++++++++++++++++++++- test/testpreprocessor.cpp | 9 +-------- 2 files changed, 28 insertions(+), 9 deletions(-) diff --git a/lib/preprocessor.cpp b/lib/preprocessor.cpp index 8050770bb..a232a432d 100644 --- a/lib/preprocessor.cpp +++ b/lib/preprocessor.cpp @@ -1330,7 +1330,33 @@ void Preprocessor::simplifyCondition(const std::map &v if (it != variables.end()) { if (!it->second.empty()) - tok->str(it->second); + { + // Tokenize the value + Tokenizer tokenizer2(&settings,NULL); + std::istringstream istr2(it->second); + tokenizer2.tokenize(istr2,"","",true); + + // Copy the value tokens + std::stack link; + for (const Token *tok2 = tokenizer2.tokens(); tok2; tok2 = tok2->next()) + { + tok->str(tok2->str()); + + if (Token::Match(tok2,"[{([]")) + link.push(tok); + else if (!link.empty() && Token::Match(tok2,"[})]]")) + { + Token::createMutualLinks(link.top(), tok); + link.pop(); + } + + if (tok2->next()) + { + tok->insertToken(""); + tok = tok->next(); + } + } + } else if ((!tok->previous() || tok->strAt(-1) == "||" || tok->strAt(-1) == "&&" || tok->strAt(-1) == "(") && (!tok->next() || tok->strAt(1) == "||" || tok->strAt(1) == "&&" || tok->strAt(1) == ")")) tok->str("1"); diff --git a/test/testpreprocessor.cpp b/test/testpreprocessor.cpp index b3ca40855..faba401a5 100644 --- a/test/testpreprocessor.cpp +++ b/test/testpreprocessor.cpp @@ -1343,18 +1343,11 @@ private: void if_cond12() { - errout.str(""); const char filedata[] = "#define A (1)\n" "#if A == 1\n" ";\n" "#endif\n"; - std::istringstream istr(filedata); - std::map actual; - Settings settings; - Preprocessor preprocessor(&settings, this); - preprocessor.preprocess(istr, actual, "file.c"); - ASSERT_EQUALS("", errout.str()); - TODO_ASSERT_EQUALS("\n\n;\n\n", "\n\n\n\n", actual[""]); + ASSERT_EQUALS("\n\n;\n\n", Preprocessor::getcode(filedata,"","",NULL,NULL)); } From c52704e636312a0c2eb399a0c0b36d20b7bf9054 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Sun, 20 Feb 2011 21:00:03 +0100 Subject: [PATCH 23/27] astyle formatting --- lib/preprocessor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/preprocessor.cpp b/lib/preprocessor.cpp index a232a432d..2f5c33795 100644 --- a/lib/preprocessor.cpp +++ b/lib/preprocessor.cpp @@ -1335,7 +1335,7 @@ void Preprocessor::simplifyCondition(const std::map &v Tokenizer tokenizer2(&settings,NULL); std::istringstream istr2(it->second); tokenizer2.tokenize(istr2,"","",true); - + // Copy the value tokens std::stack link; for (const Token *tok2 = tokenizer2.tokens(); tok2; tok2 = tok2->next()) From bfe28d3b26899fef5bca0b646a65814f7d79359c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Sun, 20 Feb 2011 21:24:57 +0100 Subject: [PATCH 24/27] Fixed #2597 (False positive: Buffer access out-of-bounds for u_char, uint*_t, ...) --- lib/checkbufferoverrun.cpp | 2 +- test/testbufferoverrun.cpp | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/lib/checkbufferoverrun.cpp b/lib/checkbufferoverrun.cpp index 4cda0ce51..ecd7aac8c 100644 --- a/lib/checkbufferoverrun.cpp +++ b/lib/checkbufferoverrun.cpp @@ -992,7 +992,7 @@ void CheckBufferOverrun::checkScope(const Token *tok, const std::vector 0) { // No varid => function calls are not handled if (varid == 0) diff --git a/test/testbufferoverrun.cpp b/test/testbufferoverrun.cpp index ba3cf9151..ecc3c7554 100644 --- a/test/testbufferoverrun.cpp +++ b/test/testbufferoverrun.cpp @@ -135,6 +135,7 @@ private: TEST_CASE(buffer_overrun_16); TEST_CASE(buffer_overrun_17); // ticket #2548 TEST_CASE(buffer_overrun_18); // ticket #2576 - for, calculation with loop variable + TEST_CASE(buffer_overrun_19); // #2597 - class member with unknown type TEST_CASE(buffer_overrun_bailoutIfSwitch); // ticket #2378 : bailoutIfSwitch // It is undefined behaviour to point out of bounds of an array @@ -1891,6 +1892,20 @@ private: errout.str()); } + void buffer_overrun_19() // #2597 - class member with unknown type + { + check("class A {\n" + "public:\n" + " u8 buf[10];\n" + " A();" + "};\n" + "\n" + "A::A() {\n" + " memset(buf, 0, 10);\n" + "}\n"); + ASSERT_EQUALS("", errout.str()); + } + void buffer_overrun_bailoutIfSwitch() { // No false positive From 763763fa9bc408fb150ac8f91c16aa06e452183b Mon Sep 17 00:00:00 2001 From: Robert Reif Date: Sun, 20 Feb 2011 18:22:49 -0500 Subject: [PATCH 25/27] fix bitfields to support non-numeric bitfield width --- lib/tokenize.cpp | 4 ++-- test/testtokenize.cpp | 13 +++++++++++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 868184a60..e718fb5e9 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -9073,7 +9073,7 @@ void Tokenizer::simplifyBitfields() { Token *last = 0; - if (Token::Match(tok, ";|{|}|public:|protected:|private: const| %type% %var% : %num% ;|,")) + if (Token::Match(tok, ";|{|}|public:|protected:|private: const| %type% %var% : %any% ;|,")) { int offset = 0; if (tok->next()->str() == "const") @@ -9082,7 +9082,7 @@ void Tokenizer::simplifyBitfields() last = tok->tokAt(5 + offset); Token::eraseTokens(tok->tokAt(2 + offset), tok->tokAt(5 + offset)); } - else if (Token::Match(tok, ";|{|}|public:|protected:|private: const| %type% : %num% ;")) + else if (Token::Match(tok, ";|{|}|public:|protected:|private: const| %type% : %any% ;")) { int offset = 0; if (tok->next()->str() == "const") diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index 02177d4bf..7b35ea570 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -279,6 +279,7 @@ private: TEST_CASE(bitfields3); TEST_CASE(bitfields4); // ticket #1956 TEST_CASE(bitfields5); // ticket #1956 + TEST_CASE(bitfields6); // ticket #2595 TEST_CASE(microsoftMFC); @@ -5083,6 +5084,18 @@ private: ASSERT_EQUALS("struct A { virtual void f ( ) { } int f1 ; } ;", tokenizeAndStringify(code3,false)); } + void bitfields6() // ticket #2595 + { + const char code1[] = "struct A { bool b : true; };"; + ASSERT_EQUALS("struct A { bool b ; } ;", tokenizeAndStringify(code1,false)); + + const char code2[] = "struct A { bool b : true, c : true; };"; + ASSERT_EQUALS("struct A { bool b ; bool c ; } ;", tokenizeAndStringify(code2,false)); + + const char code3[] = "struct A { bool : true; };"; + ASSERT_EQUALS("struct A { } ;", tokenizeAndStringify(code3,false)); + } + void microsoftMFC() { const char code1[] = "class MyDialog : public CDialog { DECLARE_MESSAGE_MAP() private: CString text; };"; From 5984b6b53f53a8f5c4b05136e6e6a1703e0a903f Mon Sep 17 00:00:00 2001 From: Robert Reif Date: Sun, 20 Feb 2011 20:01:54 -0500 Subject: [PATCH 26/27] fix #2595 (False positive Technically the member function 'A::foo' can be const) --- lib/checkclass.cpp | 8 +++++++- test/testclass.cpp | 16 ++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/lib/checkclass.cpp b/lib/checkclass.cpp index 4b9056083..4d19f2c91 100644 --- a/lib/checkclass.cpp +++ b/lib/checkclass.cpp @@ -1351,7 +1351,7 @@ bool CheckClass::isMemberVar(const Scope *scope, const Token *tok) { const Token *tok1 = tok; - while (tok->previous() && !Token::Match(tok->previous(), "}|{|;|public:|protected:|private:|return|:|?")) + while (tok->previous() && !Token::Match(tok->previous(), "}|{|;(||public:|protected:|private:|return|:|?")) { if (Token::simpleMatch(tok->previous(), "* this")) return true; @@ -1489,6 +1489,12 @@ bool CheckClass::checkConstFunc(const Scope *scope, const Token *tok) isconst = false; break; } + else if (Token::simpleMatch(tok1->previous(), ") <<") && + isMemberVar(scope, tok1->tokAt(-2))) + { + isconst = false; + break; + } // increment/decrement (member variable?).. else if (Token::Match(tok1, "++|--")) diff --git a/test/testclass.cpp b/test/testclass.cpp index f8b2515f4..7f80a053b 100644 --- a/test/testclass.cpp +++ b/test/testclass.cpp @@ -164,6 +164,7 @@ private: TEST_CASE(const41); // ticket #2255 TEST_CASE(const42); // ticket #2282 TEST_CASE(const43); // ticket #2377 + TEST_CASE(const44); // ticket #2595 TEST_CASE(assigningPointerToPointerIsNotAConstOperation); TEST_CASE(assigningArrayElementIsNotAConstOperation); TEST_CASE(constoperator1); // operator< can often be const @@ -4981,6 +4982,21 @@ private: ASSERT_EQUALS("", errout.str()); } + void const44() // ticket 2595 + { + checkConst("class A\n" + "{\n" + "public:\n" + " bool bOn;\n" + " bool foo()\n" + " {\n" + " return 0 != (bOn = bOn && true);\n" + " }\n" + "};\n"); + + ASSERT_EQUALS("", errout.str()); + } + void assigningPointerToPointerIsNotAConstOperation() { checkConst("struct s\n" From 55711698d0b51b881d13c4537914e86f43ffba31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Mon, 21 Feb 2011 19:41:34 +0100 Subject: [PATCH 27/27] Fixed #2591 (cppcheck hangs with 100% cpu load ( class A : )) --- lib/tokenize.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index e718fb5e9..cb23f4c39 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -9237,9 +9237,11 @@ void Tokenizer::simplifyBorland() // Remove Qt signals and slots void Tokenizer::simplifyQtSignalsSlots() { - Token *tok = _tokens; - while (NULL != (tok = const_cast(Token::findmatch(tok, "class %var% :")))) + for (Token *tok = _tokens; tok; tok = tok->next()) { + if (!Token::Match(tok, "class %var% :")) + continue; + if (tok->previous() && tok->previous()->str() == "enum") { tok = tok->tokAt(2);