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
|
struct VAR
|
||||||
{
|
{
|
||||||
bool is_class;
|
|
||||||
const char *name;
|
const char *name;
|
||||||
bool init;
|
bool init;
|
||||||
bool is_pointer;
|
|
||||||
struct VAR *next;
|
struct VAR *next;
|
||||||
};
|
};
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
static struct VAR *ClassChecking_GetVarList(const char classname[])
|
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..
|
// Locate class..
|
||||||
const char *pattern[] = {"class","","{",0};
|
const char *pattern[] = {"class","","{",0};
|
||||||
pattern[1] = classname;
|
pattern[1] = classname;
|
||||||
TOKEN *tok1 = findtoken(tokens, pattern);
|
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..
|
// Get variable list..
|
||||||
bool is_class = false;
|
|
||||||
bool is_pointer = false;
|
|
||||||
struct VAR *varlist = NULL;
|
struct VAR *varlist = NULL;
|
||||||
unsigned int indentlevel = 0;
|
unsigned int indentlevel = 0;
|
||||||
for (TOKEN *tok = tok1; tok; tok = tok->next)
|
for (TOKEN *tok = tok1; tok; tok = tok->next)
|
||||||
|
@ -74,51 +40,42 @@ static struct VAR *ClassChecking_GetVarList(const char classname[])
|
||||||
indentlevel--;
|
indentlevel--;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strchr(";{}", tok->str[0]))
|
|
||||||
is_class = is_pointer = false;
|
if (indentlevel==1 && (strchr(";{}", tok->str[0]) || (tok->str[0]!=':' && strchr(tok->str, ':'))))
|
||||||
else if (IsName(tok->str))
|
|
||||||
{
|
{
|
||||||
for (_class *c = classes; c; c = c->next)
|
TOKEN *next = tok->next;
|
||||||
is_class |= (strcmp(c->name, tok->str) == 0);
|
|
||||||
|
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;
|
return varlist;
|
||||||
|
@ -277,7 +234,7 @@ void CheckConstructors()
|
||||||
if (ftok)
|
if (ftok)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!var->init && (var->is_pointer || !var->is_class))
|
if (!var->init)
|
||||||
{
|
{
|
||||||
std::ostringstream ostr;
|
std::ostringstream ostr;
|
||||||
ostr << "Uninitialized member variable '" << classname << "::" << var->name << "'";
|
ostr << "Uninitialized member variable '" << classname << "::" << var->name << "'";
|
||||||
|
|
|
@ -114,7 +114,7 @@ Item0=_DEBUG
|
||||||
DebugSourceDirs=$(BCB)\source\vcl
|
DebugSourceDirs=$(BCB)\source\vcl
|
||||||
|
|
||||||
[Parameters]
|
[Parameters]
|
||||||
RunParams=-w testif5\testif5.cpp
|
RunParams=--all testUninitVar1\testUninitvar1.cpp
|
||||||
Launcher=
|
Launcher=
|
||||||
UseLauncher=0
|
UseLauncher=0
|
||||||
DebugCWD=
|
DebugCWD=
|
||||||
|
|
8
main.cpp
8
main.cpp
|
@ -107,6 +107,8 @@ static void CppCheck(const char FileName[])
|
||||||
// Buffer overruns..
|
// Buffer overruns..
|
||||||
CheckBufferOverrun();
|
CheckBufferOverrun();
|
||||||
|
|
||||||
|
// Check that all class constructors are ok.
|
||||||
|
CheckConstructors();
|
||||||
|
|
||||||
if (ShowAll)
|
if (ShowAll)
|
||||||
{
|
{
|
||||||
|
@ -117,10 +119,6 @@ static void CppCheck(const char FileName[])
|
||||||
// Disabled because it generates many false positives
|
// Disabled because it generates many false positives
|
||||||
// CheckCaseWithoutBreak();
|
// CheckCaseWithoutBreak();
|
||||||
|
|
||||||
// Check that all class constructors are ok.
|
|
||||||
// Temporarily inactivated to avoid any false positives
|
|
||||||
CheckConstructors();
|
|
||||||
|
|
||||||
// Dangerous usage of strtok
|
// Dangerous usage of strtok
|
||||||
// Disabled because it generates false positives
|
// Disabled because it generates false positives
|
||||||
//WarningStrTok();
|
//WarningStrTok();
|
||||||
|
@ -131,7 +129,7 @@ static void CppCheck(const char FileName[])
|
||||||
// Dangerous functions, such as 'gets' and 'scanf'
|
// Dangerous functions, such as 'gets' and 'scanf'
|
||||||
WarningDangerousFunctions();
|
WarningDangerousFunctions();
|
||||||
|
|
||||||
|
|
||||||
// Invalid function usage..
|
// Invalid function usage..
|
||||||
InvalidFunctionUsage();
|
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 (
|
FOR /D %%s IN (test*) DO (
|
||||||
cppcheck %%s\%%s.cpp 2> %%s\err.msg
|
cppcheck %%s\%%s.cpp 2> %%s\err.msg
|
||||||
cppcheck -w %%s\%%s.cpp 2> %%s\warn.msg
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue