This commit is contained in:
Tim Gerundt 2011-01-06 13:40:41 +01:00
commit 1a7f8ffff8
21 changed files with 290 additions and 20 deletions

View File

@ -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"

View File

@ -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;

View File

@ -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::vector<std::str
// out of bounds then this flag will be set.
bool pointerIsOutOfBounds = false;
// Count { and } for tok
int indentlevel = 0;
for (; tok; tok = tok->next())
{
@ -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;

View File

@ -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

View File

@ -86,7 +86,7 @@ void CheckNullPointer::parseFunctionCall(const Token &tok, std::list<const Token
var.push_back(tok.tokAt(2));
else if (value == 0 && Token::Match(&tok, "memchr|memcmp|memcpy|memmove|memset|strcpy|printf|sprintf|snprintf"))
var.push_back(tok.tokAt(2));
else if (Token::simpleMatch(&tok, "fflush"))
else if (value != 0 && Token::simpleMatch(&tok, "fflush"))
var.push_back(tok.tokAt(2));
}
@ -430,20 +430,28 @@ void CheckNullPointer::nullPointerStructByDeRefAndChec()
void CheckNullPointer::nullPointerByDeRefAndChec()
{
// Dereferencing a pointer and then checking if it's NULL..
// This check will first scan for the check. And then scan backwards
// from the check, searching for dereferencing.
for (const Token *tok = _tokenizer->tokens(); 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<unsigned int> 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))

View File

@ -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.");
}

View File

@ -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

View File

@ -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())
{

View File

@ -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

View File

@ -122,7 +122,7 @@ static void parseIfSwitchBody(const Token * const tok,
std::list<ExecutionPath *>::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);

View File

@ -195,6 +195,7 @@ std::string Settings::addEnabled(const std::string &str)
std::set<std::string> id;
id.insert("missingInclude");
id.insert("unusedFunction");
id.insert("information");
if (str == "all")
{

View File

@ -1574,6 +1574,41 @@ void SymbolDatabase::SpaceInfo::initializeVarList(const Func &func, std::list<st
}
// Calling member function?
else if (Token::simpleMatch(ftok, "operator = ("))
{
// check if member function exists
std::list<Func>::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

View File

@ -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 *>(Token::findmatch(tok, "class %var% :"))))
{
// count { and } for tok2
unsigned int indentlevel = 0;
for (Token *tok2 = tok; tok2; tok2 = tok2->next())
{

View File

@ -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";
}

View File

@ -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";

View File

@ -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);

View File

@ -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());
}
};

View File

@ -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)

View File

@ -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()
{
{

View File

@ -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()

View File

@ -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"