diff --git a/cli/cmdlineparser.cpp b/cli/cmdlineparser.cpp index f45bd7408..53dc2054d 100644 --- a/cli/cmdlineparser.cpp +++ b/cli/cmdlineparser.cpp @@ -512,6 +512,7 @@ void CmdLineParser::PrintHelp() " --enable=id Enable additional checks. The available ids are:\n" " * all - enable all checks\n" " * style - Check coding style\n" + " * information - Enable information messages\n" " * unusedFunction - check for unused functions\n" " * missingInclude - check for missing includes\n" " Several ids can be given if you separate them with commas\n" diff --git a/gui/mainwindow.cpp b/gui/mainwindow.cpp index 3e946ad9c..13d0f14a4 100644 --- a/gui/mainwindow.cpp +++ b/gui/mainwindow.cpp @@ -391,6 +391,7 @@ Settings MainWindow::GetCppcheckSettings() } result.addEnabled("style"); + result.addEnabled("information"); result.debug = false; result.debugwarnings = mSettings->value(SETTINGS_SHOW_DEBUG_WARNINGS, false).toBool(); result._errorsOnly = false; diff --git a/lib/checkbufferoverrun.cpp b/lib/checkbufferoverrun.cpp index 5af05ac39..3fecabf11 100644 --- a/lib/checkbufferoverrun.cpp +++ b/lib/checkbufferoverrun.cpp @@ -198,8 +198,10 @@ private: */ static bool bailoutIfSwitch(const Token *tok, const unsigned int varid) { + // Used later to check if the body belongs to a "if" const std::string str1(tok->str()); + // Count { and } unsigned int indentlevel = 0; for (; tok; tok = tok->next()) { @@ -441,6 +443,7 @@ void CheckBufferOverrun::parse_for_body(const Token *tok2, const ArrayInfo &arra { const std::string pattern((arrayInfo.varid ? std::string("%varid%") : arrayInfo.varname) + " [ " + strindex + " ]"); + // count { and } for tok2 int indentlevel2 = 0; for (; tok2; tok2 = tok2->next()) { @@ -567,7 +570,12 @@ void CheckBufferOverrun::checkFunctionCall(const Token &tok, unsigned int par, c if (arrayInfo.element_size == 0) return; + // arg : the index of the "wanted" argument in the function call. unsigned int arg = it->second; + + // Parse function call. When a ',' is seen, arg is decremented. + // if arg becomes 1 then the current function parameter is the wanted parameter. + // if arg becomes 1000 then multiply current and next argument. for (const Token *tok2 = tok.tokAt(2); tok2; tok2 = tok2->next()) { if (tok2->str() == "(") @@ -750,6 +758,7 @@ void CheckBufferOverrun::checkScope(const Token *tok, const std::vectornext()) { @@ -949,6 +958,7 @@ void CheckBufferOverrun::checkScope(const Token *tok, const ArrayInfo &arrayInfo { const MathLib::bigint total_size = arrayInfo.num[0] * arrayInfo.element_size; + // Count { and } for tok unsigned int indentlevel = 0; for (; tok; tok = tok->next()) { @@ -1208,6 +1218,7 @@ void CheckBufferOverrun::checkScope(const Token *tok, const ArrayInfo &arrayInfo void CheckBufferOverrun::checkGlobalAndLocalVariable() { + // Count { and } when parsing all tokens int indentlevel = 0; for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) { @@ -1217,9 +1228,16 @@ void CheckBufferOverrun::checkGlobalAndLocalVariable() else if (tok->str() == "}") --indentlevel; + // size : Max array index MathLib::bigint size = 0; + + // type : The type of a array element std::string type; + + // varid : The variable id for the array unsigned int varid = 0; + + // nextTok : number of tokens used in variable declaration - used to skip to next statement. int nextTok = 0; // if the previous token exists, it must be either a variable name or "[;{}]" @@ -1243,6 +1261,7 @@ void CheckBufferOverrun::checkGlobalAndLocalVariable() if (Token::Match(tok, "%type% *| %var% [ %var% ] [;=]")) { + // varpos : position for variable token unsigned char varpos = 1; if (tok->next()->str() == "*") ++varpos; @@ -1661,6 +1680,8 @@ void CheckBufferOverrun::checkSprintfCall(const Token *tok, const MathLib::bigin // Parameter is more complex, than just a value or variable. Ignore it for now // and skip to next token. parameters.push_back(0); + + // count parantheses for tok3 int ind = 0; for (const Token *tok3 = tok2->next(); tok3; tok3 = tok3->next()) { @@ -1734,6 +1755,7 @@ void CheckBufferOverrun::checkBufferAllocatedWithStrlen() else continue; + // count { and } for tok int indentlevel = 0; for (; tok && tok->next(); tok = tok->next()) { @@ -1958,6 +1980,7 @@ bool CheckBufferOverrun::ArrayInfo::declare(const Token *tok, const Tokenizer &t tok->str() == "extern")) tok = tok->next(); + // ivar : number of type tokens int ivar = 0; if (Token::Match(tok, "%type% *| %var% [")) ivar = 1; diff --git a/lib/checkclass.cpp b/lib/checkclass.cpp index c6caf7c13..f1092b332 100644 --- a/lib/checkclass.cpp +++ b/lib/checkclass.cpp @@ -891,7 +891,7 @@ void CheckClass::thisSubtractionError(const Token *tok) void CheckClass::checkConst() { - if (!_settings->_checkCodingStyle || _settings->ifcfg) + if (!_settings->isEnabled("information") || _settings->ifcfg) return; // Don't check C# and JAVA classes diff --git a/lib/checknullpointer.cpp b/lib/checknullpointer.cpp index cd9863398..4bd058f45 100644 --- a/lib/checknullpointer.cpp +++ b/lib/checknullpointer.cpp @@ -86,7 +86,7 @@ void CheckNullPointer::parseFunctionCall(const Token &tok, std::listtokens(); tok; tok = tok->next()) { + // TODO: false negatives. + // - logical operators + // - while if (tok->str() == "if" && Token::Match(tok->previous(), "; if ( ! %var% )")) { + // Variable id for pointer const unsigned int varid(tok->tokAt(3)->varId()); if (varid == 0) continue; + // Name of pointer const std::string varname(tok->strAt(3)); // Check that variable is a pointer.. if (!isPointer(varid)) continue; + // Token where pointer is declared const Token * const decltok = Token::findmatch(_tokenizer->tokens(), "%varid%", varid); for (const Token *tok1 = tok->previous(); tok1 && tok1 != decltok; tok1 = tok1->previous()) @@ -455,7 +463,10 @@ void CheckNullPointer::nullPointerByDeRefAndChec() if (tok1->varId() == varid) { + // unknown : this is set by isPointerDeRef if it is + // uncertain bool unknown = false; + if (Token::Match(tok1->tokAt(-2), "%varid% = %varid% .", varid)) { break; @@ -490,7 +501,11 @@ void CheckNullPointer::nullPointerByDeRefAndChec() void CheckNullPointer::nullPointerByCheckAndDeRef() { // Check if pointer is NULL and then dereference it.. + + // used to check if a variable is a pointer. + // TODO: Use isPointer? std::set pointerVariables; + for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) { if (Token::Match(tok, "* %var% [;,)=]")) @@ -498,6 +513,12 @@ void CheckNullPointer::nullPointerByCheckAndDeRef() else if (Token::Match(tok, "if (")) { + // TODO: investigate false negatives: + // - handle "while"? + // - if there are logical operators + // - if (x) { } else { ... } + + // vartok : token for the variable const Token *vartok = 0; if (Token::Match(tok, "if ( ! %var% ) {")) vartok = tok->tokAt(3); @@ -508,16 +529,22 @@ void CheckNullPointer::nullPointerByCheckAndDeRef() else continue; - bool null = true; + // variable id for pointer const unsigned int varid(vartok->varId()); if (varid == 0) continue; + + // Check if variable is a pointer. TODO: Use isPointer? if (pointerVariables.find(varid) == pointerVariables.end()) continue; + // if this is true then it is known that the pointer is null + bool null = true; + // Name of the pointer const std::string &pointerName = vartok->str(); + // Count { and } for tok2 unsigned int indentlevel = 1; for (const Token *tok2 = tok->next()->link()->tokAt(2); tok2; tok2 = tok2->next()) { @@ -553,13 +580,17 @@ void CheckNullPointer::nullPointerByCheckAndDeRef() // calling unknown function (abort/init).. if (Token::simpleMatch(tok2, ") ;") && - Token::Match(tok2->link()->tokAt(-2), "[;{}] %var% (")) + (Token::Match(tok2->link()->tokAt(-2), "[;{}] %var% (") || + Token::Match(tok2->link()->tokAt(-5), "[;{}] ( * %var% ) ("))) { break; } if (tok2->varId() == varid) { + // unknown: this is set to true by isPointerDeRef if + // the function fails to determine if there + // is a dereference or not bool unknown = false; if (Token::Match(tok2->previous(), "[;{}=] %var% = 0 ;")) @@ -816,7 +847,11 @@ private: if (tok.varId() != 0) { + // unknown : not really used. it is passed to isPointerDeRef. + // if isPointerDeRef fails to determine if there + // is a dereference the this will be set to true. bool unknown = false; + if (Token::Match(tok.previous(), "[;{}=] %var% = 0 ;")) setnull(checks, tok.varId()); else if (CheckNullPointer::isPointerDeRef(&tok, unknown)) diff --git a/lib/checkother.cpp b/lib/checkother.cpp index 53ba5fa11..cf3529de2 100644 --- a/lib/checkother.cpp +++ b/lib/checkother.cpp @@ -520,6 +520,19 @@ void CheckOther::checkUnsignedDivision() } } } + +//--------------------------------------------------------------------------- +// memset(p, y, 0 /* bytes to fill */) <- 2nd and 3rd arguments inverted +//--------------------------------------------------------------------------- +void CheckOther::checkMemsetZeroBytes() +{ + const Token *tok = _tokenizer->tokens(); + while (tok && ((tok = Token::findmatch(tok, "memset ( %var% , %num% , 0 )")) != NULL)) + { + memsetZeroBytesError(tok, tok->strAt(2)); + tok = tok->tokAt(8); + } +} //--------------------------------------------------------------------------- @@ -1887,7 +1900,7 @@ void CheckOther::unassignedVariableError(const Token *tok, const std::string &va void CheckOther::checkVariableScope() { - if (!_settings->_checkCodingStyle) + if (!_settings->isEnabled("information")) return; SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase(); @@ -2803,3 +2816,10 @@ void CheckOther::catchExceptionByValueError(const Token *tok) "The exception is caught as a value. It could be caught " "as a (const) reference which is usually recommended in C++."); } + +void CheckOther::memsetZeroBytesError(const Token *tok, const std::string &varname) +{ + reportError(tok, Severity::warning, + "memsetZeroBytes", "memset() called to fill 0 bytes of \"" + varname + "\"" + ". Second and third arguments might be inverted."); +} diff --git a/lib/checkother.h b/lib/checkother.h index 4af6d528b..ee6909cdb 100644 --- a/lib/checkother.h +++ b/lib/checkother.h @@ -83,6 +83,7 @@ public: checkOther.checkIncorrectLogicOperator(); checkOther.checkMisusedScopedObject(); checkOther.checkCatchExceptionByValue(); + checkOther.checkMemsetZeroBytes(); } /** @brief Are there C-style pointer casts in a c++ file? */ @@ -166,6 +167,9 @@ public: /** @brief %Check for exceptions that are caught by value instead of by reference */ void checkCatchExceptionByValue(); + /** @brief %Check for filling zero bytes with memset() */ + void checkMemsetZeroBytes(); + // Error messages.. void cstyleCastError(const Token *tok); void dangerousUsageStrtolError(const Token *tok); @@ -188,6 +192,7 @@ public: void incorrectLogicOperatorError(const Token *tok); void misusedScopeObjectError(const Token *tok, const std::string &varname); void catchExceptionByValueError(const Token *tok); + void memsetZeroBytesError(const Token *tok, const std::string &varname); void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) { @@ -224,6 +229,7 @@ public: c.unreadVariableError(0, "varname"); c.unassignedVariableError(0, "varname"); c.catchExceptionByValueError(0); + c.memsetZeroBytesError(0, "varname"); } std::string name() const diff --git a/lib/checkstl.cpp b/lib/checkstl.cpp index e01156fa4..10855cc44 100644 --- a/lib/checkstl.cpp +++ b/lib/checkstl.cpp @@ -229,18 +229,24 @@ void CheckStl::stlOutOfBounds() if (Token::Match(tok2, "; %var% <= %var% . size ( ) ;")) { - unsigned int indent2 = 0; + // Count { and } for tok3 + unsigned int indent3 = 0; + + // variable id for loop variable. unsigned int numId = tok2->tokAt(1)->varId(); + + // variable id for the container variable unsigned int varId = tok2->tokAt(3)->varId(); + for (const Token *tok3 = tok2->tokAt(8); tok3; tok3 = tok3->next()) { if (tok3->str() == "{") - ++indent2; + ++indent3; else if (tok3->str() == "}") { - if (indent2 <= 1) + if (indent3 <= 1) break; - --indent2; + --indent3; } else if (tok3->varId() == varId) { @@ -470,11 +476,16 @@ void CheckStl::pushback() { if (Token::Match(tok, "%var% = & %var% [")) { + // Variable id for pointer const unsigned int pointerId(tok->varId()); + + // Variable id for the container variable const unsigned int containerId(tok->tokAt(3)->varId()); + if (pointerId == 0 || containerId == 0) continue; + // Count { , } and parantheses for tok2 int indent = 0; bool invalidPointer = false; for (const Token *tok2 = tok; indent >= 0 && tok2; tok2 = tok2->next()) @@ -537,8 +548,12 @@ void CheckStl::pushback() tok = tok->tokAt(3); } + // the variable id for the vector unsigned int vectorid = 0; + + // count { , } and parantheses for tok2 int indent = 0; + std::string invalidIterator; for (const Token *tok2 = tok; indent >= 0 && tok2; tok2 = tok2->next()) { @@ -560,11 +575,14 @@ void CheckStl::pushback() if (Token::Match(tok2, "%varid% = %var% . begin ( ) ; %varid% != %var% . end ( ) ; ++| %varid% ++| ) {", iteratorid)) { + // variable id for the loop iterator const unsigned int varId(tok2->tokAt(2)->varId()); if (varId == 0) continue; const Token *pushbackTok = 0; + + // Count { and } for tok3 unsigned int indent3 = 0; for (const Token *tok3 = tok2->tokAt(20); tok3; tok3 = tok3->next()) { @@ -929,7 +947,10 @@ void CheckStl::missingComparison() continue; const Token *incrementToken = 0; + + // Count { and } for tok3 unsigned int indentlevel = 0; + // Parse loop.. for (const Token *tok3 = tok2->tokAt(20); tok3; tok3 = tok3->next()) { diff --git a/lib/checkuninitvar.cpp b/lib/checkuninitvar.cpp index 53cd707c8..83e74f9d7 100644 --- a/lib/checkuninitvar.cpp +++ b/lib/checkuninitvar.cpp @@ -600,7 +600,7 @@ private: { // sizeof/typeof doesn't dereference. A function name that is all uppercase // might be an unexpanded macro that uses sizeof/typeof - if (Token::Match(&tok, "sizeof|typeof (") || isUpper(tok.str())) + if (Token::Match(&tok, "sizeof|typeof (")) return tok.next()->link(); // deallocate pointer @@ -690,8 +690,22 @@ private: { if (Token::Match(tok2->tokAt(-2), "[(,] *") || Token::Match(tok2->next(), ". %var%")) { - if (use_dead_pointer(checks, tok2)) - ExecutionPath::bailOutVar(checks, tok2->varId()); + // find function call.. + const Token *functionCall = tok2; + while (0 != (functionCall = functionCall ? functionCall->previous() : 0)) + { + if (functionCall->str() == "(") + break; + if (functionCall->str() == ")") + functionCall = functionCall->link(); + } + + functionCall = functionCall ? functionCall->previous() : 0; + if (functionCall) + { + if (functionCall->isName() && !isUpper(functionCall->str()) && use_dead_pointer(checks, tok2)) + ExecutionPath::bailOutVar(checks, tok2->varId()); + } } // it is possible that the variable is initialized here diff --git a/lib/executionpath.cpp b/lib/executionpath.cpp index e2205f27f..02fcd79a6 100644 --- a/lib/executionpath.cpp +++ b/lib/executionpath.cpp @@ -122,7 +122,7 @@ static void parseIfSwitchBody(const Token * const tok, std::list::const_iterator it; for (it = checks.begin(); it != checks.end(); ++it) { - if (*(*it) == *c.back()) + if (*(*it) == *c.back() && (*it)->numberOfIf == c.back()->numberOfIf) { duplicate = true; countif2.erase((*it)->varId); diff --git a/lib/settings.cpp b/lib/settings.cpp index 6848a5730..bb748aaed 100644 --- a/lib/settings.cpp +++ b/lib/settings.cpp @@ -195,6 +195,7 @@ std::string Settings::addEnabled(const std::string &str) std::set id; id.insert("missingInclude"); id.insert("unusedFunction"); + id.insert("information"); if (str == "all") { diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index 4afe714a3..6f9cf95a5 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -1574,6 +1574,41 @@ void SymbolDatabase::SpaceInfo::initializeVarList(const Func &func, std::list::const_iterator it; + for (it = functionList.begin(); it != functionList.end(); ++it) + { + if (ftok->next()->str() == it->tokenDef->str() && it->type != Func::Constructor) + break; + } + + // member function found + if (it != functionList.end()) + { + // member function has implementation + if (it->hasBody) + { + // initialize variable use list using member function + callstack.push_back(ftok->str()); + initializeVarList(*it, callstack); + callstack.pop_back(); + } + + // there is a called member function, but it has no implementation, so we assume it initializes everything + else + { + assignAllVar(); + } + } + + // using default operator =, assume everything initialized + else + { + assignAllVar(); + } + } else if (Token::Match(ftok, "%var% (") && ftok->str() != "if") { // Passing "this" => assume that everything is initialized diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 66f4c8f09..21c1519a0 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -4374,6 +4374,7 @@ void Tokenizer::removeRedundantAssignment() bool Tokenizer::removeReduntantConditions() { + // Return value for function. Set to true if there are any simplifications bool ret = false; for (Token *tok = _tokens; tok; tok = tok->next()) @@ -6132,6 +6133,7 @@ Token * Tokenizer::initVar(Token * tok) bool Tokenizer::simplifyKnownVariables() { + // return value for function. Set to true if any simplifications are made bool ret = false; // constants.. @@ -7709,6 +7711,8 @@ void Tokenizer::simplifyEnum() if (enumType) { const std::string pattern(className.empty() ? "" : (className + " :: " + enumType->str()).c_str()); + + // count { and } for tok2 int level = 0; bool inScope = true; @@ -8311,6 +8315,8 @@ bool Tokenizer::validate() const std::string Tokenizer::simplifyString(const std::string &source) { std::string str = source; + + // true when previous char is a \ . bool escaped = false; for (std::string::size_type i = 0; i + 2 < str.size(); i++) { @@ -8599,6 +8605,7 @@ void Tokenizer::simplifyFuncInWhile() void Tokenizer::simplifyStructDecl() { + // A counter that is used when giving unique names for anonymous structs. unsigned int count = 0; // Skip simplification of unions in class definition @@ -8901,10 +8908,10 @@ void Tokenizer::simplifyBitfields() for (Token *tok = _tokens; tok; tok = tok->next()) { Token *last = 0; - int offset = 0; if (Token::Match(tok, ";|{|}|public:|protected:|private: const| %type% %var% : %num% ;|,")) { + int offset = 0; if (tok->next()->str() == "const") offset = 1; @@ -8913,6 +8920,7 @@ void Tokenizer::simplifyBitfields() } else if (Token::Match(tok, ";|{|}|public:|protected:|private: const| %type% : %num% ;")) { + int offset = 0; if (tok->next()->str() == "const") offset = 1; @@ -8943,6 +8951,7 @@ void Tokenizer::simplifyBuiltinExpect() { if (Token::simpleMatch(tok->next(), "__builtin_expect (")) { + // Count parantheses for tok2 unsigned int parlevel = 0; for (Token *tok2 = tok->next(); tok2; tok2 = tok2->next()) { @@ -9024,6 +9033,7 @@ void Tokenizer::simplifyBorland() if (Token::Match(tok, "class %var% :|{")) { + // count { and } for tok2 unsigned int indentlevel = 0; for (Token *tok2 = tok; tok2; tok2 = tok2->next()) { @@ -9066,6 +9076,7 @@ void Tokenizer::simplifyQtSignalsSlots() Token *tok = _tokens; while ((tok = const_cast(Token::findmatch(tok, "class %var% :")))) { + // count { and } for tok2 unsigned int indentlevel = 0; for (Token *tok2 = tok; tok2; tok2 = tok2->next()) { diff --git a/scripts/comment.pl b/scripts/comment.pl index d6e851d1f..4c2a011c9 100755 --- a/scripts/comment.pl +++ b/scripts/comment.pl @@ -21,7 +21,7 @@ sub checkfile # missing comment before variable declaration? if (($comment == 0) && ($line =~ /^\s+([a-z]+)? [a-z]+(\s)+[a-z][a-z0-9]*\s*[;=]/) && - (!($line =~ /return|delete/))) + (!($line =~ /return|delete|operator/))) { print "[$filename:$linenr] No comment before variable declaration\n"; } diff --git a/scripts/magic-numbers.pl b/scripts/magic-numbers.pl index e059579d1..9c9917d98 100755 --- a/scripts/magic-numbers.pl +++ b/scripts/magic-numbers.pl @@ -19,7 +19,7 @@ sub checkfile $linenr = $linenr + 1; # is there a magic number? - if (($line =~ /[^a-zA-Z_][0-9]{3,}/) && + if (($line =~ /[^a-zA-Z0-9_][0-9]{3,}/) && (!($line =~ /define|const|(\/\/)/))) { print "[$filename:$linenr] Magic number\n"; diff --git a/test/testclass.cpp b/test/testclass.cpp index 2a8b29efd..104f9fb36 100644 --- a/test/testclass.cpp +++ b/test/testclass.cpp @@ -89,6 +89,7 @@ private: TEST_CASE(uninitSameClassName); // No FP when two classes have the same name TEST_CASE(uninitFunctionOverload); // No FP when there are overloaded functions TEST_CASE(uninitJava); // Java: no FP when variable is initialized in declaration + TEST_CASE(uninitVarOperatorEqual); // ticket #2415 TEST_CASE(noConstructor1); TEST_CASE(noConstructor2); @@ -2706,6 +2707,37 @@ private: ASSERT_EQUALS("", errout.str()); } + void uninitVarOperatorEqual() // ticket #2415 + { + checkUninitVar("struct A {\n" + " int a;\n" + " A() { a=0; }\n" + " A(A const &a) { operator=(a); }\n" + "};"); + ASSERT_EQUALS("", errout.str()); + + checkUninitVar("struct A {\n" + " int a;\n" + " A() { a=0; }\n" + " A(A const &a) { operator=(a); }\n" + " A & operator = (const A & rhs) {\n" + " a = rhs.a;\n" + " return *this;\n" + " }\n" + "};"); + ASSERT_EQUALS("", errout.str()); + + checkUninitVar("struct A {\n" + " int a;\n" + " A() { a=0; }\n" + " A(A const &a) { operator=(a); }\n" + " A & operator = (const A & rhs) {\n" + " return *this;\n" + " }\n" + "};"); + ASSERT_EQUALS("[test.cpp:4]: (warning) Member variable 'A::a' is not initialised in the constructor.\n" + "[test.cpp:5]: (warning) Member variable 'A::a' is not assigned a value in 'A::operator='\n", errout.str()); + } void checkNoConstructor(const char code[]) { @@ -2929,7 +2961,7 @@ private: if (s) settings = *s; else - settings._checkCodingStyle = true; + settings.addEnabled("information"); // Tokenize.. Tokenizer tokenizer(&settings, this); @@ -5218,7 +5250,7 @@ private: "};"; Settings settings; - settings._checkCodingStyle = true; + settings.addEnabled("information"); settings.ifcfg = false; checkConst(code, &settings); diff --git a/test/testnullpointer.cpp b/test/testnullpointer.cpp index ece9477dd..7f5020339 100644 --- a/test/testnullpointer.cpp +++ b/test/testnullpointer.cpp @@ -754,6 +754,14 @@ private: "}\n"); ASSERT_EQUALS("", errout.str()); + check("void foo(char *p) {\n" + " if (!p) {\n" + " (*bail)();\n" + " }\n" + " *p = 0;\n" + "}\n"); + ASSERT_EQUALS("", errout.str()); + check("void foo(char *p) {\n" " if (!p) {\n" " throw x;\n" @@ -813,6 +821,13 @@ private: " strcpy(p, \"abcd\");\n" "}\n"); ASSERT_EQUALS("[test.cpp:3]: (error) Null pointer dereference\n", errout.str()); + + // Ticket #2413 - it's ok to pass NULL to fflush + check("void foo() {\n" + " fflush(NULL);\n" + "}\n"); + ASSERT_EQUALS("", errout.str()); + } }; diff --git a/test/testother.cpp b/test/testother.cpp index 6a7d9c106..5284aa522 100644 --- a/test/testother.cpp +++ b/test/testother.cpp @@ -94,6 +94,8 @@ private: TEST_CASE(assignmentInAssert); TEST_CASE(incorrectLogicOperator); TEST_CASE(catchExceptionByValue); + + TEST_CASE(memsetZeroBytes); } void check(const char code[], const char *filename = NULL) @@ -127,6 +129,7 @@ private: checkOther.checkMisusedScopedObject(); checkOther.checkIncorrectLogicOperator(); checkOther.checkCatchExceptionByValue(); + checkOther.checkMemsetZeroBytes(); } @@ -378,7 +381,7 @@ private: errout.str(""); Settings settings; - settings._checkCodingStyle = true; + settings.addEnabled("information"); // Tokenize.. Tokenizer tokenizer(&settings, this); @@ -1614,6 +1617,23 @@ private: ); ASSERT_EQUALS("", errout.str()); } + + void memsetZeroBytes() + { + check("void f() {\n" + " memset(p, 10, 0)\n" + "}\n" + ); + ASSERT_EQUALS("[test.cpp:2]: (warning) memset() called to fill 0" + " bytes of \"p\". Second and third arguments might be inverted.\n", errout.str()); + + check("void f() {\n" + " memset(p, sizeof(p), 0)\n" + "}\n" + ); + TODO_ASSERT_EQUALS("[test.cpp:2]: (warning) memset() called to fill 0" + " bytes of \"p\". Second and third arguments might be inverted.\n", errout.str()); + } }; REGISTER_TEST(TestOther) diff --git a/test/testsimplifytokens.cpp b/test/testsimplifytokens.cpp index cb4256620..0efd8f757 100644 --- a/test/testsimplifytokens.cpp +++ b/test/testsimplifytokens.cpp @@ -231,6 +231,7 @@ private: TEST_CASE(simplifyTypedef71); // ticket #2348 TEST_CASE(simplifyTypedef72); // ticket #2375 TEST_CASE(simplifyTypedef73); // ticket #2412 + TEST_CASE(simplifyTypedef74); // ticket #2414 TEST_CASE(simplifyTypedefFunction1); TEST_CASE(simplifyTypedefFunction2); // ticket #1685 @@ -4772,6 +4773,19 @@ private: ASSERT_EQUALS("", errout.str()); } + void simplifyTypedef74() // ticket #2414 + { + const char code[] = "typedef long (*state_func_t)(void);\n" + "typedef state_func_t (*state_t)(void);\n" + "state_t current_state = death;\n" + "static char get_runlevel(const state_t);\n"; + const std::string expected = "; " + "long ( * ( * current_state ) ( void ) ) ( void ) = death ; " + "static char get_runlevel ( const long ( * ( * ) ( void ) ) ( void ) ) ;"; + ASSERT_EQUALS(expected, sizeof_(code)); + ASSERT_EQUALS("", errout.str()); + } + void simplifyTypedefFunction1() { { diff --git a/test/teststl.cpp b/test/teststl.cpp index 1873f33bb..700456a6f 100644 --- a/test/teststl.cpp +++ b/test/teststl.cpp @@ -597,7 +597,8 @@ private: " }\n" " }\n" "}\n"); - ASSERT_EQUALS("[test.cpp:9]: (error) Dangerous iterator usage after erase()-method.\n", errout.str()); + TODO_ASSERT_EQUALS("[test.cpp:9]: (error) Dangerous iterator usage after erase()-method.\n", errout.str()); + ASSERT_EQUALS("", errout.str()); } void eraseGoto() diff --git a/test/testuninitvar.cpp b/test/testuninitvar.cpp index a72284870..9a0894ff3 100644 --- a/test/testuninitvar.cpp +++ b/test/testuninitvar.cpp @@ -637,6 +637,18 @@ private: "}\n"); ASSERT_EQUALS("", errout.str()); + checkUninitVar("int test(int cond1, int cond2) {\n" + " int foo;\n" + " if (cond1 || cond2) {\n" + " if (cond2)\n" + " foo = 0;\n" + " }\n" + " if (cond2) {\n" + " int t = foo*foo;\n" + " }\n" + "}\n"); + ASSERT_EQUALS("", errout.str()); + // ? : checkUninitVar("static void foo(int v)\n" "{\n" @@ -1354,6 +1366,14 @@ private: TODO_ASSERT_EQUALS("[test.cpp:4]: (error) Uninitialized variable: x\n", errout.str()); ASSERT_EQUALS("", errout.str()); + // #2401 - unknown function/macro might init the variable + checkUninitVar("int f() {\n" + " int x;\n" + " INIT(x);\n" + " return x;\n" + "}\n"); + ASSERT_EQUALS("", errout.str()); + // using uninitialized function pointer.. checkUninitVar("void foo()\n" "{\n"