check for uninitialized variables - less generic to increase accuracy

This commit is contained in:
Daniel Marjamäki 2008-01-10 19:01:16 +00:00
parent 2d8a6d3f47
commit a770561de4
45 changed files with 56 additions and 112 deletions

View File

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

View File

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

View File

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

1
testUninitVar1/err.msg Normal file
View File

@ -0,0 +1 @@
Uninitialized member variable 'Fred::_i'

View File

@ -0,0 +1,15 @@
class Fred
{
private:
int _i;
public:
Fred();
Fred(int);
}
Fred::Fred()
{ }
Fred::Fred(int i)
{ }

View File

@ -1 +0,0 @@
[testbufferoverrun1\testbufferoverrun1.cpp:7]: Array index out of bounds

View File

@ -1 +0,0 @@
[testbufferoverrun2\testbufferoverrun2.cpp:7]: Buffer overrun

View File

@ -1 +0,0 @@
[testbufferoverrun4\testbufferoverrun4.cpp:6]: Buffer overrun

View File

@ -1 +0,0 @@
[testbufferoverrun5\testbufferoverrun5.cpp:8]: Array index out of bounds

View File

@ -1 +0,0 @@
[testbufferoverrun6\testbufferoverrun6.cpp:8]: Array index out of bounds

View File

View File

View File

@ -1 +0,0 @@
[testclass12\testclass12.cpp:5]: 'operator=' should return something

View File

@ -0,0 +1 @@
Uninitialized member variable 'clKalle::i'

View File

@ -1 +0,0 @@
Uninitialized member variable 'clKalle::i'

View File

View File

View File

View File

View File

@ -1 +0,0 @@
[testcond1\testcond1.cpp:5]: Possible bug. Should it be '==' instead of '='?

View File

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

View File

@ -1 +0,0 @@
[testdelete1\testdelete1.cpp:6]: Redundant condition. It is safe to deallocate a NULL pointer

View File

View File

View File

@ -1 +0,0 @@
[testfunc4\testfunc4.cpp:5]: Invalid radix in call to strtol or strtoul. Must be 0 or 2-36

View File

@ -1 +0,0 @@
[testfunc6\testfunc6.cpp:6]: Found "if (condition) var = true;", it can be rewritten as "var |= (condition);"

View File

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

View File

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

View File

@ -1 +0,0 @@
[testh3\testh3.cpp:2]: The included header 'testh3\h1.h' is not needed

View File

View File

@ -1 +0,0 @@
[testif1\testif1.cpp:5]: Found "if (condition);"

View File

@ -1 +0,0 @@
[testif2\testif2.cpp:6]: The condition is always False

View File

View File

View File

@ -1 +0,0 @@
[testif5\testif5.cpp:5]: Found "if (condition) var=true; else var=false;", it can be rewritten as "var = (condition);"

View File

@ -1 +0,0 @@
[testmemcheck1\testmemcheck1.cpp:5]: Mismatching allocation and deallocation 'a'

View File

View File

View File

@ -1 +0,0 @@
[testmemcheck4\testmemcheck4.cpp:9]: Memory leak:str

View File

View File

View File

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

View File

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

View File

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