Warn about memset(this, 0, sizeof(*this)); (#1285)

This commit is contained in:
PKEuS 2013-02-16 11:02:43 -08:00
parent 167e11b645
commit 711d0d7a33
2 changed files with 29 additions and 7 deletions

View File

@ -797,6 +797,16 @@ void CheckClass::unusedPrivateFunctionError(const Token *tok, const std::string
// ClassCheck: Check that memset is not used on classes // ClassCheck: Check that memset is not used on classes
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
const Scope* findFunctionOf(const Scope* scope)
{
while (scope) {
if (scope->type == Scope::eFunction)
return scope->functionOf;
scope = scope->nestedIn;
}
return 0;
}
void CheckClass::noMemset() void CheckClass::noMemset()
{ {
const std::size_t functions = symbolDatabase->functionScopes.size(); const std::size_t functions = symbolDatabase->functionScopes.size();
@ -813,27 +823,30 @@ void CheckClass::noMemset()
arg3 = arg3->nextArgument(); arg3 = arg3->nextArgument();
const Token *typeTok = 0; const Token *typeTok = 0;
const Scope *type = 0;
if (Token::Match(arg3, "sizeof ( %type% ) )")) if (Token::Match(arg3, "sizeof ( %type% ) )"))
typeTok = arg3->tokAt(2); typeTok = arg3->tokAt(2);
else if (Token::Match(arg3, "sizeof ( %type% :: %type% ) )")) else if (Token::Match(arg3, "sizeof ( %type% :: %type% ) )"))
typeTok = arg3->tokAt(4); typeTok = arg3->tokAt(4);
else if (Token::Match(arg3, "sizeof ( struct %type% ) )")) else if (Token::Match(arg3, "sizeof ( struct %type% ) )"))
typeTok = arg3->tokAt(3); typeTok = arg3->tokAt(3);
else if (Token::Match(arg1, "&| %var% ,")) { else if (Token::simpleMatch(arg3, "sizeof ( * this ) )") || Token::simpleMatch(arg1, "this ,")) {
type = findFunctionOf(arg3->scope());
} else if (Token::Match(arg1, "&| %var% ,")) {
const Variable *var = arg1->str() == "&" ? arg1->next()->variable() : arg1->variable(); const Variable *var = arg1->str() == "&" ? arg1->next()->variable() : arg1->variable();
if (var && (var->typeStartToken() == var->typeEndToken() || Token::Match(var->typeStartToken(), "%type% :: %type%")) if (var && (arg1->str() == "&" || var->isPointer() || var->isArray()))
&& (arg1->str() == "&" || var->isPointer() || var->isArray())) type = var->type();
typeTok = var->typeEndToken();
} }
// No type defined => The tokens didn't match // No type defined => The tokens didn't match
if (!typeTok) if (!typeTok && !type)
continue; continue;
if (typeTok->str() == "(") if (typeTok && typeTok->str() == "(")
typeTok = typeTok->next(); typeTok = typeTok->next();
const Scope *type = symbolDatabase->findVariableType(&(*scope), typeTok); if (!type)
type = symbolDatabase->findVariableType(&(*scope), typeTok);
if (type) if (type)
checkMemsetType(&(*scope), tok, type); checkMemsetType(&(*scope), tok, type);

View File

@ -2014,6 +2014,15 @@ private:
"}\n"); "}\n");
ASSERT_EQUALS("[test.cpp:8]: (error) Using 'memset' on class that contains a 'std::string'.\n", errout.str()); ASSERT_EQUALS("[test.cpp:8]: (error) Using 'memset' on class that contains a 'std::string'.\n", errout.str());
checkNoMemset("class Fred {\n"
" std::string b;\n"
" void f();\n"
"};\n"
"void Fred::f() {\n"
" memset(this, 0, sizeof(*this));\n"
"}");
ASSERT_EQUALS("[test.cpp:6]: (error) Using 'memset' on class that contains a 'std::string'.\n", errout.str());
checkNoMemset("class Fred\n" checkNoMemset("class Fred\n"
"{\n" "{\n"
"};\n" "};\n"