Merge branch 'master' of https://github.com/danmar/cppcheck
This commit is contained in:
commit
1a7f8ffff8
|
@ -512,6 +512,7 @@ void CmdLineParser::PrintHelp()
|
||||||
" --enable=id Enable additional checks. The available ids are:\n"
|
" --enable=id Enable additional checks. The available ids are:\n"
|
||||||
" * all - enable all checks\n"
|
" * all - enable all checks\n"
|
||||||
" * style - Check coding style\n"
|
" * style - Check coding style\n"
|
||||||
|
" * information - Enable information messages\n"
|
||||||
" * unusedFunction - check for unused functions\n"
|
" * unusedFunction - check for unused functions\n"
|
||||||
" * missingInclude - check for missing includes\n"
|
" * missingInclude - check for missing includes\n"
|
||||||
" Several ids can be given if you separate them with commas\n"
|
" Several ids can be given if you separate them with commas\n"
|
||||||
|
|
|
@ -391,6 +391,7 @@ Settings MainWindow::GetCppcheckSettings()
|
||||||
}
|
}
|
||||||
|
|
||||||
result.addEnabled("style");
|
result.addEnabled("style");
|
||||||
|
result.addEnabled("information");
|
||||||
result.debug = false;
|
result.debug = false;
|
||||||
result.debugwarnings = mSettings->value(SETTINGS_SHOW_DEBUG_WARNINGS, false).toBool();
|
result.debugwarnings = mSettings->value(SETTINGS_SHOW_DEBUG_WARNINGS, false).toBool();
|
||||||
result._errorsOnly = false;
|
result._errorsOnly = false;
|
||||||
|
|
|
@ -198,8 +198,10 @@ private:
|
||||||
*/
|
*/
|
||||||
static bool bailoutIfSwitch(const Token *tok, const unsigned int varid)
|
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());
|
const std::string str1(tok->str());
|
||||||
|
|
||||||
|
// Count { and }
|
||||||
unsigned int indentlevel = 0;
|
unsigned int indentlevel = 0;
|
||||||
for (; tok; tok = tok->next())
|
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 + " ]");
|
const std::string pattern((arrayInfo.varid ? std::string("%varid%") : arrayInfo.varname) + " [ " + strindex + " ]");
|
||||||
|
|
||||||
|
// count { and } for tok2
|
||||||
int indentlevel2 = 0;
|
int indentlevel2 = 0;
|
||||||
for (; tok2; tok2 = tok2->next())
|
for (; tok2; tok2 = tok2->next())
|
||||||
{
|
{
|
||||||
|
@ -567,7 +570,12 @@ void CheckBufferOverrun::checkFunctionCall(const Token &tok, unsigned int par, c
|
||||||
if (arrayInfo.element_size == 0)
|
if (arrayInfo.element_size == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// arg : the index of the "wanted" argument in the function call.
|
||||||
unsigned int arg = it->second;
|
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())
|
for (const Token *tok2 = tok.tokAt(2); tok2; tok2 = tok2->next())
|
||||||
{
|
{
|
||||||
if (tok2->str() == "(")
|
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.
|
// out of bounds then this flag will be set.
|
||||||
bool pointerIsOutOfBounds = false;
|
bool pointerIsOutOfBounds = false;
|
||||||
|
|
||||||
|
// Count { and } for tok
|
||||||
int indentlevel = 0;
|
int indentlevel = 0;
|
||||||
for (; tok; tok = tok->next())
|
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;
|
const MathLib::bigint total_size = arrayInfo.num[0] * arrayInfo.element_size;
|
||||||
|
|
||||||
|
// Count { and } for tok
|
||||||
unsigned int indentlevel = 0;
|
unsigned int indentlevel = 0;
|
||||||
for (; tok; tok = tok->next())
|
for (; tok; tok = tok->next())
|
||||||
{
|
{
|
||||||
|
@ -1208,6 +1218,7 @@ void CheckBufferOverrun::checkScope(const Token *tok, const ArrayInfo &arrayInfo
|
||||||
|
|
||||||
void CheckBufferOverrun::checkGlobalAndLocalVariable()
|
void CheckBufferOverrun::checkGlobalAndLocalVariable()
|
||||||
{
|
{
|
||||||
|
// Count { and } when parsing all tokens
|
||||||
int indentlevel = 0;
|
int indentlevel = 0;
|
||||||
for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next())
|
for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next())
|
||||||
{
|
{
|
||||||
|
@ -1217,9 +1228,16 @@ void CheckBufferOverrun::checkGlobalAndLocalVariable()
|
||||||
else if (tok->str() == "}")
|
else if (tok->str() == "}")
|
||||||
--indentlevel;
|
--indentlevel;
|
||||||
|
|
||||||
|
// size : Max array index
|
||||||
MathLib::bigint size = 0;
|
MathLib::bigint size = 0;
|
||||||
|
|
||||||
|
// type : The type of a array element
|
||||||
std::string type;
|
std::string type;
|
||||||
|
|
||||||
|
// varid : The variable id for the array
|
||||||
unsigned int varid = 0;
|
unsigned int varid = 0;
|
||||||
|
|
||||||
|
// nextTok : number of tokens used in variable declaration - used to skip to next statement.
|
||||||
int nextTok = 0;
|
int nextTok = 0;
|
||||||
|
|
||||||
// if the previous token exists, it must be either a variable name or "[;{}]"
|
// 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% ] [;=]"))
|
if (Token::Match(tok, "%type% *| %var% [ %var% ] [;=]"))
|
||||||
{
|
{
|
||||||
|
// varpos : position for variable token
|
||||||
unsigned char varpos = 1;
|
unsigned char varpos = 1;
|
||||||
if (tok->next()->str() == "*")
|
if (tok->next()->str() == "*")
|
||||||
++varpos;
|
++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
|
// Parameter is more complex, than just a value or variable. Ignore it for now
|
||||||
// and skip to next token.
|
// and skip to next token.
|
||||||
parameters.push_back(0);
|
parameters.push_back(0);
|
||||||
|
|
||||||
|
// count parantheses for tok3
|
||||||
int ind = 0;
|
int ind = 0;
|
||||||
for (const Token *tok3 = tok2->next(); tok3; tok3 = tok3->next())
|
for (const Token *tok3 = tok2->next(); tok3; tok3 = tok3->next())
|
||||||
{
|
{
|
||||||
|
@ -1734,6 +1755,7 @@ void CheckBufferOverrun::checkBufferAllocatedWithStrlen()
|
||||||
else
|
else
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
// count { and } for tok
|
||||||
int indentlevel = 0;
|
int indentlevel = 0;
|
||||||
for (; tok && tok->next(); tok = tok->next())
|
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->str() == "extern"))
|
||||||
tok = tok->next();
|
tok = tok->next();
|
||||||
|
|
||||||
|
// ivar : number of type tokens
|
||||||
int ivar = 0;
|
int ivar = 0;
|
||||||
if (Token::Match(tok, "%type% *| %var% ["))
|
if (Token::Match(tok, "%type% *| %var% ["))
|
||||||
ivar = 1;
|
ivar = 1;
|
||||||
|
|
|
@ -891,7 +891,7 @@ void CheckClass::thisSubtractionError(const Token *tok)
|
||||||
|
|
||||||
void CheckClass::checkConst()
|
void CheckClass::checkConst()
|
||||||
{
|
{
|
||||||
if (!_settings->_checkCodingStyle || _settings->ifcfg)
|
if (!_settings->isEnabled("information") || _settings->ifcfg)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Don't check C# and JAVA classes
|
// Don't check C# and JAVA classes
|
||||||
|
|
|
@ -86,7 +86,7 @@ void CheckNullPointer::parseFunctionCall(const Token &tok, std::list<const Token
|
||||||
var.push_back(tok.tokAt(2));
|
var.push_back(tok.tokAt(2));
|
||||||
else if (value == 0 && Token::Match(&tok, "memchr|memcmp|memcpy|memmove|memset|strcpy|printf|sprintf|snprintf"))
|
else if (value == 0 && Token::Match(&tok, "memchr|memcmp|memcpy|memmove|memset|strcpy|printf|sprintf|snprintf"))
|
||||||
var.push_back(tok.tokAt(2));
|
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));
|
var.push_back(tok.tokAt(2));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -430,20 +430,28 @@ void CheckNullPointer::nullPointerStructByDeRefAndChec()
|
||||||
void CheckNullPointer::nullPointerByDeRefAndChec()
|
void CheckNullPointer::nullPointerByDeRefAndChec()
|
||||||
{
|
{
|
||||||
// Dereferencing a pointer and then checking if it's NULL..
|
// 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())
|
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% )"))
|
if (tok->str() == "if" && Token::Match(tok->previous(), "; if ( ! %var% )"))
|
||||||
{
|
{
|
||||||
|
// Variable id for pointer
|
||||||
const unsigned int varid(tok->tokAt(3)->varId());
|
const unsigned int varid(tok->tokAt(3)->varId());
|
||||||
if (varid == 0)
|
if (varid == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
// Name of pointer
|
||||||
const std::string varname(tok->strAt(3));
|
const std::string varname(tok->strAt(3));
|
||||||
|
|
||||||
// Check that variable is a pointer..
|
// Check that variable is a pointer..
|
||||||
if (!isPointer(varid))
|
if (!isPointer(varid))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
// Token where pointer is declared
|
||||||
const Token * const decltok = Token::findmatch(_tokenizer->tokens(), "%varid%", varid);
|
const Token * const decltok = Token::findmatch(_tokenizer->tokens(), "%varid%", varid);
|
||||||
|
|
||||||
for (const Token *tok1 = tok->previous(); tok1 && tok1 != decltok; tok1 = tok1->previous())
|
for (const Token *tok1 = tok->previous(); tok1 && tok1 != decltok; tok1 = tok1->previous())
|
||||||
|
@ -455,7 +463,10 @@ void CheckNullPointer::nullPointerByDeRefAndChec()
|
||||||
|
|
||||||
if (tok1->varId() == varid)
|
if (tok1->varId() == varid)
|
||||||
{
|
{
|
||||||
|
// unknown : this is set by isPointerDeRef if it is
|
||||||
|
// uncertain
|
||||||
bool unknown = false;
|
bool unknown = false;
|
||||||
|
|
||||||
if (Token::Match(tok1->tokAt(-2), "%varid% = %varid% .", varid))
|
if (Token::Match(tok1->tokAt(-2), "%varid% = %varid% .", varid))
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
|
@ -490,7 +501,11 @@ void CheckNullPointer::nullPointerByDeRefAndChec()
|
||||||
void CheckNullPointer::nullPointerByCheckAndDeRef()
|
void CheckNullPointer::nullPointerByCheckAndDeRef()
|
||||||
{
|
{
|
||||||
// Check if pointer is NULL and then dereference it..
|
// 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;
|
std::set<unsigned int> pointerVariables;
|
||||||
|
|
||||||
for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next())
|
for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next())
|
||||||
{
|
{
|
||||||
if (Token::Match(tok, "* %var% [;,)=]"))
|
if (Token::Match(tok, "* %var% [;,)=]"))
|
||||||
|
@ -498,6 +513,12 @@ void CheckNullPointer::nullPointerByCheckAndDeRef()
|
||||||
|
|
||||||
else if (Token::Match(tok, "if ("))
|
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;
|
const Token *vartok = 0;
|
||||||
if (Token::Match(tok, "if ( ! %var% ) {"))
|
if (Token::Match(tok, "if ( ! %var% ) {"))
|
||||||
vartok = tok->tokAt(3);
|
vartok = tok->tokAt(3);
|
||||||
|
@ -508,16 +529,22 @@ void CheckNullPointer::nullPointerByCheckAndDeRef()
|
||||||
else
|
else
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
bool null = true;
|
// variable id for pointer
|
||||||
const unsigned int varid(vartok->varId());
|
const unsigned int varid(vartok->varId());
|
||||||
if (varid == 0)
|
if (varid == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
// Check if variable is a pointer. TODO: Use isPointer?
|
||||||
if (pointerVariables.find(varid) == pointerVariables.end())
|
if (pointerVariables.find(varid) == pointerVariables.end())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
// if this is true then it is known that the pointer is null
|
||||||
|
bool null = true;
|
||||||
|
|
||||||
// Name of the pointer
|
// Name of the pointer
|
||||||
const std::string &pointerName = vartok->str();
|
const std::string &pointerName = vartok->str();
|
||||||
|
|
||||||
|
// Count { and } for tok2
|
||||||
unsigned int indentlevel = 1;
|
unsigned int indentlevel = 1;
|
||||||
for (const Token *tok2 = tok->next()->link()->tokAt(2); tok2; tok2 = tok2->next())
|
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)..
|
// calling unknown function (abort/init)..
|
||||||
if (Token::simpleMatch(tok2, ") ;") &&
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tok2->varId() == varid)
|
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;
|
bool unknown = false;
|
||||||
|
|
||||||
if (Token::Match(tok2->previous(), "[;{}=] %var% = 0 ;"))
|
if (Token::Match(tok2->previous(), "[;{}=] %var% = 0 ;"))
|
||||||
|
@ -816,7 +847,11 @@ private:
|
||||||
|
|
||||||
if (tok.varId() != 0)
|
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;
|
bool unknown = false;
|
||||||
|
|
||||||
if (Token::Match(tok.previous(), "[;{}=] %var% = 0 ;"))
|
if (Token::Match(tok.previous(), "[;{}=] %var% = 0 ;"))
|
||||||
setnull(checks, tok.varId());
|
setnull(checks, tok.varId());
|
||||||
else if (CheckNullPointer::isPointerDeRef(&tok, unknown))
|
else if (CheckNullPointer::isPointerDeRef(&tok, unknown))
|
||||||
|
|
|
@ -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()
|
void CheckOther::checkVariableScope()
|
||||||
{
|
{
|
||||||
if (!_settings->_checkCodingStyle)
|
if (!_settings->isEnabled("information"))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase();
|
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 "
|
"The exception is caught as a value. It could be caught "
|
||||||
"as a (const) reference which is usually recommended in C++.");
|
"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.");
|
||||||
|
}
|
||||||
|
|
|
@ -83,6 +83,7 @@ public:
|
||||||
checkOther.checkIncorrectLogicOperator();
|
checkOther.checkIncorrectLogicOperator();
|
||||||
checkOther.checkMisusedScopedObject();
|
checkOther.checkMisusedScopedObject();
|
||||||
checkOther.checkCatchExceptionByValue();
|
checkOther.checkCatchExceptionByValue();
|
||||||
|
checkOther.checkMemsetZeroBytes();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @brief Are there C-style pointer casts in a c++ file? */
|
/** @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 */
|
/** @brief %Check for exceptions that are caught by value instead of by reference */
|
||||||
void checkCatchExceptionByValue();
|
void checkCatchExceptionByValue();
|
||||||
|
|
||||||
|
/** @brief %Check for filling zero bytes with memset() */
|
||||||
|
void checkMemsetZeroBytes();
|
||||||
|
|
||||||
// Error messages..
|
// Error messages..
|
||||||
void cstyleCastError(const Token *tok);
|
void cstyleCastError(const Token *tok);
|
||||||
void dangerousUsageStrtolError(const Token *tok);
|
void dangerousUsageStrtolError(const Token *tok);
|
||||||
|
@ -188,6 +192,7 @@ public:
|
||||||
void incorrectLogicOperatorError(const Token *tok);
|
void incorrectLogicOperatorError(const Token *tok);
|
||||||
void misusedScopeObjectError(const Token *tok, const std::string &varname);
|
void misusedScopeObjectError(const Token *tok, const std::string &varname);
|
||||||
void catchExceptionByValueError(const Token *tok);
|
void catchExceptionByValueError(const Token *tok);
|
||||||
|
void memsetZeroBytesError(const Token *tok, const std::string &varname);
|
||||||
|
|
||||||
void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings)
|
void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings)
|
||||||
{
|
{
|
||||||
|
@ -224,6 +229,7 @@ public:
|
||||||
c.unreadVariableError(0, "varname");
|
c.unreadVariableError(0, "varname");
|
||||||
c.unassignedVariableError(0, "varname");
|
c.unassignedVariableError(0, "varname");
|
||||||
c.catchExceptionByValueError(0);
|
c.catchExceptionByValueError(0);
|
||||||
|
c.memsetZeroBytesError(0, "varname");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string name() const
|
std::string name() const
|
||||||
|
|
|
@ -229,18 +229,24 @@ void CheckStl::stlOutOfBounds()
|
||||||
|
|
||||||
if (Token::Match(tok2, "; %var% <= %var% . size ( ) ;"))
|
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();
|
unsigned int numId = tok2->tokAt(1)->varId();
|
||||||
|
|
||||||
|
// variable id for the container variable
|
||||||
unsigned int varId = tok2->tokAt(3)->varId();
|
unsigned int varId = tok2->tokAt(3)->varId();
|
||||||
|
|
||||||
for (const Token *tok3 = tok2->tokAt(8); tok3; tok3 = tok3->next())
|
for (const Token *tok3 = tok2->tokAt(8); tok3; tok3 = tok3->next())
|
||||||
{
|
{
|
||||||
if (tok3->str() == "{")
|
if (tok3->str() == "{")
|
||||||
++indent2;
|
++indent3;
|
||||||
else if (tok3->str() == "}")
|
else if (tok3->str() == "}")
|
||||||
{
|
{
|
||||||
if (indent2 <= 1)
|
if (indent3 <= 1)
|
||||||
break;
|
break;
|
||||||
--indent2;
|
--indent3;
|
||||||
}
|
}
|
||||||
else if (tok3->varId() == varId)
|
else if (tok3->varId() == varId)
|
||||||
{
|
{
|
||||||
|
@ -470,11 +476,16 @@ void CheckStl::pushback()
|
||||||
{
|
{
|
||||||
if (Token::Match(tok, "%var% = & %var% ["))
|
if (Token::Match(tok, "%var% = & %var% ["))
|
||||||
{
|
{
|
||||||
|
// Variable id for pointer
|
||||||
const unsigned int pointerId(tok->varId());
|
const unsigned int pointerId(tok->varId());
|
||||||
|
|
||||||
|
// Variable id for the container variable
|
||||||
const unsigned int containerId(tok->tokAt(3)->varId());
|
const unsigned int containerId(tok->tokAt(3)->varId());
|
||||||
|
|
||||||
if (pointerId == 0 || containerId == 0)
|
if (pointerId == 0 || containerId == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
// Count { , } and parantheses for tok2
|
||||||
int indent = 0;
|
int indent = 0;
|
||||||
bool invalidPointer = false;
|
bool invalidPointer = false;
|
||||||
for (const Token *tok2 = tok; indent >= 0 && tok2; tok2 = tok2->next())
|
for (const Token *tok2 = tok; indent >= 0 && tok2; tok2 = tok2->next())
|
||||||
|
@ -537,8 +548,12 @@ void CheckStl::pushback()
|
||||||
tok = tok->tokAt(3);
|
tok = tok->tokAt(3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// the variable id for the vector
|
||||||
unsigned int vectorid = 0;
|
unsigned int vectorid = 0;
|
||||||
|
|
||||||
|
// count { , } and parantheses for tok2
|
||||||
int indent = 0;
|
int indent = 0;
|
||||||
|
|
||||||
std::string invalidIterator;
|
std::string invalidIterator;
|
||||||
for (const Token *tok2 = tok; indent >= 0 && tok2; tok2 = tok2->next())
|
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))
|
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());
|
const unsigned int varId(tok2->tokAt(2)->varId());
|
||||||
if (varId == 0)
|
if (varId == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
const Token *pushbackTok = 0;
|
const Token *pushbackTok = 0;
|
||||||
|
|
||||||
|
// Count { and } for tok3
|
||||||
unsigned int indent3 = 0;
|
unsigned int indent3 = 0;
|
||||||
for (const Token *tok3 = tok2->tokAt(20); tok3; tok3 = tok3->next())
|
for (const Token *tok3 = tok2->tokAt(20); tok3; tok3 = tok3->next())
|
||||||
{
|
{
|
||||||
|
@ -929,7 +947,10 @@ void CheckStl::missingComparison()
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
const Token *incrementToken = 0;
|
const Token *incrementToken = 0;
|
||||||
|
|
||||||
|
// Count { and } for tok3
|
||||||
unsigned int indentlevel = 0;
|
unsigned int indentlevel = 0;
|
||||||
|
|
||||||
// Parse loop..
|
// Parse loop..
|
||||||
for (const Token *tok3 = tok2->tokAt(20); tok3; tok3 = tok3->next())
|
for (const Token *tok3 = tok2->tokAt(20); tok3; tok3 = tok3->next())
|
||||||
{
|
{
|
||||||
|
|
|
@ -600,7 +600,7 @@ private:
|
||||||
{
|
{
|
||||||
// sizeof/typeof doesn't dereference. A function name that is all uppercase
|
// sizeof/typeof doesn't dereference. A function name that is all uppercase
|
||||||
// might be an unexpanded macro that uses sizeof/typeof
|
// 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();
|
return tok.next()->link();
|
||||||
|
|
||||||
// deallocate pointer
|
// deallocate pointer
|
||||||
|
@ -690,8 +690,22 @@ private:
|
||||||
{
|
{
|
||||||
if (Token::Match(tok2->tokAt(-2), "[(,] *") || Token::Match(tok2->next(), ". %var%"))
|
if (Token::Match(tok2->tokAt(-2), "[(,] *") || Token::Match(tok2->next(), ". %var%"))
|
||||||
{
|
{
|
||||||
if (use_dead_pointer(checks, tok2))
|
// find function call..
|
||||||
ExecutionPath::bailOutVar(checks, tok2->varId());
|
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
|
// it is possible that the variable is initialized here
|
||||||
|
|
|
@ -122,7 +122,7 @@ static void parseIfSwitchBody(const Token * const tok,
|
||||||
std::list<ExecutionPath *>::const_iterator it;
|
std::list<ExecutionPath *>::const_iterator it;
|
||||||
for (it = checks.begin(); it != checks.end(); ++it)
|
for (it = checks.begin(); it != checks.end(); ++it)
|
||||||
{
|
{
|
||||||
if (*(*it) == *c.back())
|
if (*(*it) == *c.back() && (*it)->numberOfIf == c.back()->numberOfIf)
|
||||||
{
|
{
|
||||||
duplicate = true;
|
duplicate = true;
|
||||||
countif2.erase((*it)->varId);
|
countif2.erase((*it)->varId);
|
||||||
|
|
|
@ -195,6 +195,7 @@ std::string Settings::addEnabled(const std::string &str)
|
||||||
std::set<std::string> id;
|
std::set<std::string> id;
|
||||||
id.insert("missingInclude");
|
id.insert("missingInclude");
|
||||||
id.insert("unusedFunction");
|
id.insert("unusedFunction");
|
||||||
|
id.insert("information");
|
||||||
|
|
||||||
if (str == "all")
|
if (str == "all")
|
||||||
{
|
{
|
||||||
|
|
|
@ -1574,6 +1574,41 @@ void SymbolDatabase::SpaceInfo::initializeVarList(const Func &func, std::list<st
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calling member function?
|
// 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")
|
else if (Token::Match(ftok, "%var% (") && ftok->str() != "if")
|
||||||
{
|
{
|
||||||
// Passing "this" => assume that everything is initialized
|
// Passing "this" => assume that everything is initialized
|
||||||
|
|
|
@ -4374,6 +4374,7 @@ void Tokenizer::removeRedundantAssignment()
|
||||||
|
|
||||||
bool Tokenizer::removeReduntantConditions()
|
bool Tokenizer::removeReduntantConditions()
|
||||||
{
|
{
|
||||||
|
// Return value for function. Set to true if there are any simplifications
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
|
|
||||||
for (Token *tok = _tokens; tok; tok = tok->next())
|
for (Token *tok = _tokens; tok; tok = tok->next())
|
||||||
|
@ -6132,6 +6133,7 @@ Token * Tokenizer::initVar(Token * tok)
|
||||||
|
|
||||||
bool Tokenizer::simplifyKnownVariables()
|
bool Tokenizer::simplifyKnownVariables()
|
||||||
{
|
{
|
||||||
|
// return value for function. Set to true if any simplifications are made
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
|
|
||||||
// constants..
|
// constants..
|
||||||
|
@ -7709,6 +7711,8 @@ void Tokenizer::simplifyEnum()
|
||||||
if (enumType)
|
if (enumType)
|
||||||
{
|
{
|
||||||
const std::string pattern(className.empty() ? "" : (className + " :: " + enumType->str()).c_str());
|
const std::string pattern(className.empty() ? "" : (className + " :: " + enumType->str()).c_str());
|
||||||
|
|
||||||
|
// count { and } for tok2
|
||||||
int level = 0;
|
int level = 0;
|
||||||
bool inScope = true;
|
bool inScope = true;
|
||||||
|
|
||||||
|
@ -8311,6 +8315,8 @@ bool Tokenizer::validate() const
|
||||||
std::string Tokenizer::simplifyString(const std::string &source)
|
std::string Tokenizer::simplifyString(const std::string &source)
|
||||||
{
|
{
|
||||||
std::string str = source;
|
std::string str = source;
|
||||||
|
|
||||||
|
// true when previous char is a \ .
|
||||||
bool escaped = false;
|
bool escaped = false;
|
||||||
for (std::string::size_type i = 0; i + 2 < str.size(); i++)
|
for (std::string::size_type i = 0; i + 2 < str.size(); i++)
|
||||||
{
|
{
|
||||||
|
@ -8599,6 +8605,7 @@ void Tokenizer::simplifyFuncInWhile()
|
||||||
|
|
||||||
void Tokenizer::simplifyStructDecl()
|
void Tokenizer::simplifyStructDecl()
|
||||||
{
|
{
|
||||||
|
// A counter that is used when giving unique names for anonymous structs.
|
||||||
unsigned int count = 0;
|
unsigned int count = 0;
|
||||||
|
|
||||||
// Skip simplification of unions in class definition
|
// Skip simplification of unions in class definition
|
||||||
|
@ -8901,10 +8908,10 @@ void Tokenizer::simplifyBitfields()
|
||||||
for (Token *tok = _tokens; tok; tok = tok->next())
|
for (Token *tok = _tokens; tok; tok = tok->next())
|
||||||
{
|
{
|
||||||
Token *last = 0;
|
Token *last = 0;
|
||||||
int offset = 0;
|
|
||||||
|
|
||||||
if (Token::Match(tok, ";|{|}|public:|protected:|private: const| %type% %var% : %num% ;|,"))
|
if (Token::Match(tok, ";|{|}|public:|protected:|private: const| %type% %var% : %num% ;|,"))
|
||||||
{
|
{
|
||||||
|
int offset = 0;
|
||||||
if (tok->next()->str() == "const")
|
if (tok->next()->str() == "const")
|
||||||
offset = 1;
|
offset = 1;
|
||||||
|
|
||||||
|
@ -8913,6 +8920,7 @@ void Tokenizer::simplifyBitfields()
|
||||||
}
|
}
|
||||||
else if (Token::Match(tok, ";|{|}|public:|protected:|private: const| %type% : %num% ;"))
|
else if (Token::Match(tok, ";|{|}|public:|protected:|private: const| %type% : %num% ;"))
|
||||||
{
|
{
|
||||||
|
int offset = 0;
|
||||||
if (tok->next()->str() == "const")
|
if (tok->next()->str() == "const")
|
||||||
offset = 1;
|
offset = 1;
|
||||||
|
|
||||||
|
@ -8943,6 +8951,7 @@ void Tokenizer::simplifyBuiltinExpect()
|
||||||
{
|
{
|
||||||
if (Token::simpleMatch(tok->next(), "__builtin_expect ("))
|
if (Token::simpleMatch(tok->next(), "__builtin_expect ("))
|
||||||
{
|
{
|
||||||
|
// Count parantheses for tok2
|
||||||
unsigned int parlevel = 0;
|
unsigned int parlevel = 0;
|
||||||
for (Token *tok2 = tok->next(); tok2; tok2 = tok2->next())
|
for (Token *tok2 = tok->next(); tok2; tok2 = tok2->next())
|
||||||
{
|
{
|
||||||
|
@ -9024,6 +9033,7 @@ void Tokenizer::simplifyBorland()
|
||||||
|
|
||||||
if (Token::Match(tok, "class %var% :|{"))
|
if (Token::Match(tok, "class %var% :|{"))
|
||||||
{
|
{
|
||||||
|
// count { and } for tok2
|
||||||
unsigned int indentlevel = 0;
|
unsigned int indentlevel = 0;
|
||||||
for (Token *tok2 = tok; tok2; tok2 = tok2->next())
|
for (Token *tok2 = tok; tok2; tok2 = tok2->next())
|
||||||
{
|
{
|
||||||
|
@ -9066,6 +9076,7 @@ void Tokenizer::simplifyQtSignalsSlots()
|
||||||
Token *tok = _tokens;
|
Token *tok = _tokens;
|
||||||
while ((tok = const_cast<Token *>(Token::findmatch(tok, "class %var% :"))))
|
while ((tok = const_cast<Token *>(Token::findmatch(tok, "class %var% :"))))
|
||||||
{
|
{
|
||||||
|
// count { and } for tok2
|
||||||
unsigned int indentlevel = 0;
|
unsigned int indentlevel = 0;
|
||||||
for (Token *tok2 = tok; tok2; tok2 = tok2->next())
|
for (Token *tok2 = tok; tok2; tok2 = tok2->next())
|
||||||
{
|
{
|
||||||
|
|
|
@ -21,7 +21,7 @@ sub checkfile
|
||||||
# missing comment before variable declaration?
|
# missing comment before variable declaration?
|
||||||
if (($comment == 0) &&
|
if (($comment == 0) &&
|
||||||
($line =~ /^\s+([a-z]+)? [a-z]+(\s)+[a-z][a-z0-9]*\s*[;=]/) &&
|
($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";
|
print "[$filename:$linenr] No comment before variable declaration\n";
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,7 @@ sub checkfile
|
||||||
$linenr = $linenr + 1;
|
$linenr = $linenr + 1;
|
||||||
|
|
||||||
# is there a magic number?
|
# 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|(\/\/)/)))
|
(!($line =~ /define|const|(\/\/)/)))
|
||||||
{
|
{
|
||||||
print "[$filename:$linenr] Magic number\n";
|
print "[$filename:$linenr] Magic number\n";
|
||||||
|
|
|
@ -89,6 +89,7 @@ private:
|
||||||
TEST_CASE(uninitSameClassName); // No FP when two classes have the same name
|
TEST_CASE(uninitSameClassName); // No FP when two classes have the same name
|
||||||
TEST_CASE(uninitFunctionOverload); // No FP when there are overloaded functions
|
TEST_CASE(uninitFunctionOverload); // No FP when there are overloaded functions
|
||||||
TEST_CASE(uninitJava); // Java: no FP when variable is initialized in declaration
|
TEST_CASE(uninitJava); // Java: no FP when variable is initialized in declaration
|
||||||
|
TEST_CASE(uninitVarOperatorEqual); // ticket #2415
|
||||||
|
|
||||||
TEST_CASE(noConstructor1);
|
TEST_CASE(noConstructor1);
|
||||||
TEST_CASE(noConstructor2);
|
TEST_CASE(noConstructor2);
|
||||||
|
@ -2706,6 +2707,37 @@ private:
|
||||||
ASSERT_EQUALS("", errout.str());
|
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[])
|
void checkNoConstructor(const char code[])
|
||||||
{
|
{
|
||||||
|
@ -2929,7 +2961,7 @@ private:
|
||||||
if (s)
|
if (s)
|
||||||
settings = *s;
|
settings = *s;
|
||||||
else
|
else
|
||||||
settings._checkCodingStyle = true;
|
settings.addEnabled("information");
|
||||||
|
|
||||||
// Tokenize..
|
// Tokenize..
|
||||||
Tokenizer tokenizer(&settings, this);
|
Tokenizer tokenizer(&settings, this);
|
||||||
|
@ -5218,7 +5250,7 @@ private:
|
||||||
"};";
|
"};";
|
||||||
|
|
||||||
Settings settings;
|
Settings settings;
|
||||||
settings._checkCodingStyle = true;
|
settings.addEnabled("information");
|
||||||
|
|
||||||
settings.ifcfg = false;
|
settings.ifcfg = false;
|
||||||
checkConst(code, &settings);
|
checkConst(code, &settings);
|
||||||
|
|
|
@ -754,6 +754,14 @@ private:
|
||||||
"}\n");
|
"}\n");
|
||||||
ASSERT_EQUALS("", errout.str());
|
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"
|
check("void foo(char *p) {\n"
|
||||||
" if (!p) {\n"
|
" if (!p) {\n"
|
||||||
" throw x;\n"
|
" throw x;\n"
|
||||||
|
@ -813,6 +821,13 @@ private:
|
||||||
" strcpy(p, \"abcd\");\n"
|
" strcpy(p, \"abcd\");\n"
|
||||||
"}\n");
|
"}\n");
|
||||||
ASSERT_EQUALS("[test.cpp:3]: (error) Null pointer dereference\n", errout.str());
|
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());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -94,6 +94,8 @@ private:
|
||||||
TEST_CASE(assignmentInAssert);
|
TEST_CASE(assignmentInAssert);
|
||||||
TEST_CASE(incorrectLogicOperator);
|
TEST_CASE(incorrectLogicOperator);
|
||||||
TEST_CASE(catchExceptionByValue);
|
TEST_CASE(catchExceptionByValue);
|
||||||
|
|
||||||
|
TEST_CASE(memsetZeroBytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
void check(const char code[], const char *filename = NULL)
|
void check(const char code[], const char *filename = NULL)
|
||||||
|
@ -127,6 +129,7 @@ private:
|
||||||
checkOther.checkMisusedScopedObject();
|
checkOther.checkMisusedScopedObject();
|
||||||
checkOther.checkIncorrectLogicOperator();
|
checkOther.checkIncorrectLogicOperator();
|
||||||
checkOther.checkCatchExceptionByValue();
|
checkOther.checkCatchExceptionByValue();
|
||||||
|
checkOther.checkMemsetZeroBytes();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -378,7 +381,7 @@ private:
|
||||||
errout.str("");
|
errout.str("");
|
||||||
|
|
||||||
Settings settings;
|
Settings settings;
|
||||||
settings._checkCodingStyle = true;
|
settings.addEnabled("information");
|
||||||
|
|
||||||
// Tokenize..
|
// Tokenize..
|
||||||
Tokenizer tokenizer(&settings, this);
|
Tokenizer tokenizer(&settings, this);
|
||||||
|
@ -1614,6 +1617,23 @@ private:
|
||||||
);
|
);
|
||||||
ASSERT_EQUALS("", errout.str());
|
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)
|
REGISTER_TEST(TestOther)
|
||||||
|
|
|
@ -231,6 +231,7 @@ private:
|
||||||
TEST_CASE(simplifyTypedef71); // ticket #2348
|
TEST_CASE(simplifyTypedef71); // ticket #2348
|
||||||
TEST_CASE(simplifyTypedef72); // ticket #2375
|
TEST_CASE(simplifyTypedef72); // ticket #2375
|
||||||
TEST_CASE(simplifyTypedef73); // ticket #2412
|
TEST_CASE(simplifyTypedef73); // ticket #2412
|
||||||
|
TEST_CASE(simplifyTypedef74); // ticket #2414
|
||||||
|
|
||||||
TEST_CASE(simplifyTypedefFunction1);
|
TEST_CASE(simplifyTypedefFunction1);
|
||||||
TEST_CASE(simplifyTypedefFunction2); // ticket #1685
|
TEST_CASE(simplifyTypedefFunction2); // ticket #1685
|
||||||
|
@ -4772,6 +4773,19 @@ private:
|
||||||
ASSERT_EQUALS("", errout.str());
|
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()
|
void simplifyTypedefFunction1()
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
|
|
|
@ -597,7 +597,8 @@ private:
|
||||||
" }\n"
|
" }\n"
|
||||||
" }\n"
|
" }\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()
|
void eraseGoto()
|
||||||
|
|
|
@ -637,6 +637,18 @@ private:
|
||||||
"}\n");
|
"}\n");
|
||||||
ASSERT_EQUALS("", errout.str());
|
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"
|
checkUninitVar("static void foo(int v)\n"
|
||||||
"{\n"
|
"{\n"
|
||||||
|
@ -1354,6 +1366,14 @@ private:
|
||||||
TODO_ASSERT_EQUALS("[test.cpp:4]: (error) Uninitialized variable: x\n", errout.str());
|
TODO_ASSERT_EQUALS("[test.cpp:4]: (error) Uninitialized variable: x\n", errout.str());
|
||||||
ASSERT_EQUALS("", 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..
|
// using uninitialized function pointer..
|
||||||
checkUninitVar("void foo()\n"
|
checkUninitVar("void foo()\n"
|
||||||
"{\n"
|
"{\n"
|
||||||
|
|
Loading…
Reference in New Issue