check for uninitialized variables - less generic to increase accuracy
This commit is contained in:
parent
2d8a6d3f47
commit
a770561de4
113
CheckClass.cpp
113
CheckClass.cpp
|
@ -10,54 +10,20 @@
|
|||
|
||||
struct VAR
|
||||
{
|
||||
bool is_class;
|
||||
const char *name;
|
||||
bool init;
|
||||
bool is_pointer;
|
||||
struct VAR *next;
|
||||
};
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
static struct VAR *ClassChecking_GetVarList(const char classname[])
|
||||
{
|
||||
// Get all initialized types..
|
||||
std::vector<const char *> InitializedTypes;
|
||||
for (TOKEN *tok = tokens; tok; tok = tok->next)
|
||||
{
|
||||
// "typedef std::" => This is a initialized type
|
||||
if (match(tok,"typedef std ::"))
|
||||
{
|
||||
while (tok->next && tok->next->str[0]!=';')
|
||||
tok = tok->next;
|
||||
InitializedTypes.push_back(tok->str);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Locate class..
|
||||
const char *pattern[] = {"class","","{",0};
|
||||
pattern[1] = classname;
|
||||
TOKEN *tok1 = findtoken(tokens, pattern);
|
||||
|
||||
// All classes..
|
||||
struct _class
|
||||
{
|
||||
const char *name;
|
||||
struct _class *next;
|
||||
};
|
||||
struct _class *classes = NULL;
|
||||
const char *pattern_anyclass[] = {"class","",NULL};
|
||||
for (TOKEN *t = findtoken(tokens,pattern_anyclass); t; t = findtoken(t->next,pattern_anyclass))
|
||||
{
|
||||
_class *newclass = new _class;
|
||||
newclass->name = t->next->str;
|
||||
newclass->next = classes;
|
||||
classes = newclass;
|
||||
}
|
||||
|
||||
// Get variable list..
|
||||
bool is_class = false;
|
||||
bool is_pointer = false;
|
||||
struct VAR *varlist = NULL;
|
||||
unsigned int indentlevel = 0;
|
||||
for (TOKEN *tok = tok1; tok; tok = tok->next)
|
||||
|
@ -74,51 +40,42 @@ static struct VAR *ClassChecking_GetVarList(const char classname[])
|
|||
indentlevel--;
|
||||
}
|
||||
|
||||
if (strchr(";{}", tok->str[0]))
|
||||
is_class = is_pointer = false;
|
||||
else if (IsName(tok->str))
|
||||
|
||||
if (indentlevel==1 && (strchr(";{}", tok->str[0]) || (tok->str[0]!=':' && strchr(tok->str, ':'))))
|
||||
{
|
||||
for (_class *c = classes; c; c = c->next)
|
||||
is_class |= (strcmp(c->name, tok->str) == 0);
|
||||
TOKEN *next = tok->next;
|
||||
|
||||
const char *varname = 0;
|
||||
|
||||
// Is it a variable declaration?
|
||||
if ( match(next,"var var ;") )
|
||||
{
|
||||
const char *types[] = {"bool", "char", "int", "short", "long", "float", "double", 0};
|
||||
for ( int type = 0; types[type]; type++ )
|
||||
{
|
||||
if ( strcmp(next->str, types[type]) == 0)
|
||||
{
|
||||
varname = next->next->str;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Pointer?
|
||||
else if ( match(next, "var * var ;") )
|
||||
{
|
||||
varname = getstr(next, 2);
|
||||
}
|
||||
|
||||
if (varname)
|
||||
{
|
||||
struct VAR *var = new VAR;
|
||||
memset(var, 0, sizeof(struct VAR));
|
||||
var->name = varname;
|
||||
var->next = varlist;
|
||||
varlist = var;
|
||||
}
|
||||
}
|
||||
|
||||
bool initializedtype = false;
|
||||
for (unsigned int i = 0; i < InitializedTypes.size(); i++)
|
||||
initializedtype |= (strcmp(tok->str,InitializedTypes[i])==0);
|
||||
|
||||
// "std::" => This variable is initialized
|
||||
if (match(tok,"std ::") || initializedtype)
|
||||
{
|
||||
while (tok->next && tok->next->str[0] != ';')
|
||||
tok = tok->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (tok->str[0] == '*')
|
||||
is_pointer = true;
|
||||
|
||||
// Member variable?
|
||||
if ((indentlevel == 1) &&
|
||||
(tok->next->str[0] == ';') &&
|
||||
(strchr(tok->str,':')==0) &&
|
||||
(IsName(tok->str)) &&
|
||||
(strcmp(tok->str,"const") != 0 ))
|
||||
{
|
||||
struct VAR *var = new VAR;
|
||||
memset(var, 0, sizeof(struct VAR));
|
||||
var->name = tok->str;
|
||||
var->next = varlist;
|
||||
var->is_class = is_class;
|
||||
var->is_pointer = is_pointer;
|
||||
varlist = var;
|
||||
}
|
||||
}
|
||||
|
||||
while (classes)
|
||||
{
|
||||
_class *next = classes->next;
|
||||
delete classes;
|
||||
classes = next;
|
||||
}
|
||||
|
||||
return varlist;
|
||||
|
@ -277,7 +234,7 @@ void CheckConstructors()
|
|||
if (ftok)
|
||||
continue;
|
||||
|
||||
if (!var->init && (var->is_pointer || !var->is_class))
|
||||
if (!var->init)
|
||||
{
|
||||
std::ostringstream ostr;
|
||||
ostr << "Uninitialized member variable '" << classname << "::" << var->name << "'";
|
||||
|
|
|
@ -114,7 +114,7 @@ Item0=_DEBUG
|
|||
DebugSourceDirs=$(BCB)\source\vcl
|
||||
|
||||
[Parameters]
|
||||
RunParams=-w testif5\testif5.cpp
|
||||
RunParams=--all testUninitVar1\testUninitvar1.cpp
|
||||
Launcher=
|
||||
UseLauncher=0
|
||||
DebugCWD=
|
||||
|
|
8
main.cpp
8
main.cpp
|
@ -107,6 +107,8 @@ static void CppCheck(const char FileName[])
|
|||
// Buffer overruns..
|
||||
CheckBufferOverrun();
|
||||
|
||||
// Check that all class constructors are ok.
|
||||
CheckConstructors();
|
||||
|
||||
if (ShowAll)
|
||||
{
|
||||
|
@ -117,10 +119,6 @@ static void CppCheck(const char FileName[])
|
|||
// Disabled because it generates many false positives
|
||||
// CheckCaseWithoutBreak();
|
||||
|
||||
// Check that all class constructors are ok.
|
||||
// Temporarily inactivated to avoid any false positives
|
||||
CheckConstructors();
|
||||
|
||||
// Dangerous usage of strtok
|
||||
// Disabled because it generates false positives
|
||||
//WarningStrTok();
|
||||
|
@ -131,7 +129,7 @@ static void CppCheck(const char FileName[])
|
|||
// Dangerous functions, such as 'gets' and 'scanf'
|
||||
WarningDangerousFunctions();
|
||||
|
||||
|
||||
|
||||
// Invalid function usage..
|
||||
InvalidFunctionUsage();
|
||||
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Uninitialized member variable 'Fred::_i'
|
|
@ -0,0 +1,15 @@
|
|||
|
||||
class Fred
|
||||
{
|
||||
private:
|
||||
int _i;
|
||||
public:
|
||||
Fred();
|
||||
Fred(int);
|
||||
}
|
||||
|
||||
Fred::Fred()
|
||||
{ }
|
||||
|
||||
Fred::Fred(int i)
|
||||
{ }
|
|
@ -1 +0,0 @@
|
|||
[testbufferoverrun1\testbufferoverrun1.cpp:7]: Array index out of bounds
|
|
@ -1 +0,0 @@
|
|||
[testbufferoverrun2\testbufferoverrun2.cpp:7]: Buffer overrun
|
|
@ -1 +0,0 @@
|
|||
[testbufferoverrun4\testbufferoverrun4.cpp:6]: Buffer overrun
|
|
@ -1 +0,0 @@
|
|||
[testbufferoverrun5\testbufferoverrun5.cpp:8]: Array index out of bounds
|
|
@ -1 +0,0 @@
|
|||
[testbufferoverrun6\testbufferoverrun6.cpp:8]: Array index out of bounds
|
|
@ -1 +0,0 @@
|
|||
[testclass12\testclass12.cpp:5]: 'operator=' should return something
|
|
@ -0,0 +1 @@
|
|||
Uninitialized member variable 'clKalle::i'
|
|
@ -1 +0,0 @@
|
|||
Uninitialized member variable 'clKalle::i'
|
|
@ -1 +0,0 @@
|
|||
[testcond1\testcond1.cpp:5]: Possible bug. Should it be '==' instead of '='?
|
|
@ -1,2 +0,0 @@
|
|||
[testdangerousfunc1\testdangerousfunc1.cpp:4]: Found 'gets'. You should use 'fgets' instead
|
||||
[testdangerousfunc1\testdangerousfunc1.cpp:7]: Found 'scanf'. You should use 'fgets' instead
|
|
@ -1 +0,0 @@
|
|||
[testdelete1\testdelete1.cpp:6]: Redundant condition. It is safe to deallocate a NULL pointer
|
|
@ -1 +0,0 @@
|
|||
[testfunc4\testfunc4.cpp:5]: Invalid radix in call to strtol or strtoul. Must be 0 or 2-36
|
|
@ -1 +0,0 @@
|
|||
[testfunc6\testfunc6.cpp:6]: Found "if (condition) var = true;", it can be rewritten as "var |= (condition);"
|
|
@ -1,2 +0,0 @@
|
|||
[testh1\testh1.cpp:2]: The included header 'testh1\testh1.h' is not needed
|
||||
[testh1\testh1.h:5]: Found implementation in header
|
|
@ -1,2 +0,0 @@
|
|||
[testh2\testh2.cpp:2]: The included header 'testh2\testh2.h' is not needed
|
||||
[testh2\testh2.h:2]: The included header 'testh2\emptyh.h' is not needed
|
|
@ -1 +0,0 @@
|
|||
[testh3\testh3.cpp:2]: The included header 'testh3\h1.h' is not needed
|
|
@ -1 +0,0 @@
|
|||
[testif1\testif1.cpp:5]: Found "if (condition);"
|
|
@ -1 +0,0 @@
|
|||
[testif2\testif2.cpp:6]: The condition is always False
|
|
@ -1 +0,0 @@
|
|||
[testif5\testif5.cpp:5]: Found "if (condition) var=true; else var=false;", it can be rewritten as "var = (condition);"
|
|
@ -1 +0,0 @@
|
|||
[testmemcheck1\testmemcheck1.cpp:5]: Mismatching allocation and deallocation 'a'
|
|
@ -1 +0,0 @@
|
|||
[testmemcheck4\testmemcheck4.cpp:9]: Memory leak:str
|
|
@ -1,2 +0,0 @@
|
|||
[testmemset1\testmemset1.cpp:28]: Using 'memset' on class.
|
||||
[testmemset1\testmemset1.cpp:34]: Using 'memset' on struct that contains a 'std::string'
|
|
@ -1,2 +0,0 @@
|
|||
[teststdfunc1\teststdfunc1.cpp:4]: The condition can be simplified; use 'isdigit'
|
||||
[teststdfunc1\teststdfunc1.cpp:9]: The condition can be simplified; use 'isdigit'
|
|
@ -3,7 +3,6 @@
|
|||
|
||||
FOR /D %%s IN (test*) DO (
|
||||
cppcheck %%s\%%s.cpp 2> %%s\err.msg
|
||||
cppcheck -w %%s\%%s.cpp 2> %%s\warn.msg
|
||||
)
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue