From a40c1e9eb74f5a5852a08b3255c6b7eb41fb7288 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Tue, 19 Feb 2008 07:09:09 +0000 Subject: [PATCH] CheckClass: Improved constructor checking --- CheckClass.cpp | 71 ++++++++++++++++++++++------- tests.cpp | 118 +++++++++++++++++++++++++++++++++++++------------ 2 files changed, 146 insertions(+), 43 deletions(-) diff --git a/CheckClass.cpp b/CheckClass.cpp index 6b1e5be76..d326b62c5 100644 --- a/CheckClass.cpp +++ b/CheckClass.cpp @@ -90,18 +90,53 @@ static struct VAR *ClassChecking_GetVarList(const char classname[]) } //--------------------------------------------------------------------------- -static TOKEN * ClassChecking_VarList_Initialize(TOKEN *_tokens, struct VAR *varlist, const char classname[], const char funcname[]) +static TOKEN * FindClassFunction( TOKEN *_tokens, const char classname[], const char funcname[], unsigned int &indentlevel ) { - // Locate class member function - const char *pattern[] = {"","::","","(",NULL}; - pattern[0] = classname; - pattern[2] = funcname; + while ( _tokens ) + { + if ( indentlevel > 0 ) + { + if ( _tokens->str[0] == '{' ) + indentlevel++; + else if ( _tokens->str[0] == '}' ) + indentlevel--; + else if ( indentlevel == 1 ) + { + // Member function is implemented in the class declaration.. + if ( match( _tokens, "var (" ) && strcmp(_tokens->str,funcname) == 0 ) + { + TOKEN *tok2 = _tokens; + while ( tok2 && tok2->str[0] != '{' && tok2->str[0] != ';' ) + tok2 = tok2->next; + if ( tok2 && tok2->str[0] == '{' ) + return _tokens; + } + } + } - // Locate member function implementation.. - TOKEN *ftok = findtoken(_tokens, pattern); - if (!ftok) - return NULL; + else if ( match(_tokens, "class var {") && strcmp(getstr(_tokens,1),classname)==0 ) + { + indentlevel = 1; + _tokens = gettok( _tokens, 2 ); + } + else if ( match(_tokens, "var :: var (") && + strcmp(_tokens->str,classname) == 0 && + strcmp(getstr(_tokens,2),funcname) == 0 ) + { + return _tokens; + } + + _tokens = _tokens->next; + } + + // Not found + return NULL; +} +//--------------------------------------------------------------------------- + +static void ClassChecking_VarList_Initialize(TOKEN *ftok, struct VAR *varlist, const char classname[]) +{ bool BeginLine = false; bool Assign = false; unsigned int indentlevel = 0; @@ -112,7 +147,7 @@ static TOKEN * ClassChecking_VarList_Initialize(TOKEN *_tokens, struct VAR *varl // Class constructor.. initializing variables like this // clKalle::clKalle() : var(value) { } - if (indentlevel==0 && strcmp(classname,funcname)==0) + if (indentlevel==0) { if (Assign && IsName(ftok->str) && @@ -155,7 +190,11 @@ static TOKEN * ClassChecking_VarList_Initialize(TOKEN *_tokens, struct VAR *varl // Calling member function? if (ftok->next->str[0] == '(') - ClassChecking_VarList_Initialize(tokens, varlist, classname, ftok->str); + { + unsigned int i = 0; + TOKEN *ftok2 = FindClassFunction( tokens, classname, ftok->str, i ); + ClassChecking_VarList_Initialize(ftok2, varlist, classname); + } // Assignment of member variable? if (strcmp(ftok->next->str, "=") == 0) @@ -192,8 +231,6 @@ static TOKEN * ClassChecking_VarList_Initialize(TOKEN *_tokens, struct VAR *varl BeginLine = (strchr("{};", ftok->str[0])); } - - return ftok; } @@ -238,7 +275,9 @@ void CheckConstructors() // Check that all member variables are initialized.. struct VAR *varlist = ClassChecking_GetVarList(classname); - constructor_token = ClassChecking_VarList_Initialize(tokens, varlist, classname, classname); + unsigned int indentlevel = 0; + constructor_token = FindClassFunction( tokens, classname, classname, indentlevel ); + ClassChecking_VarList_Initialize(constructor_token, varlist, classname); while ( constructor_token ) { // Check if any variables are uninitialized @@ -262,7 +301,9 @@ void CheckConstructors() for ( struct VAR *var = varlist; var; var = var->next ) var->init = false; - constructor_token = ClassChecking_VarList_Initialize(constructor_token->next, varlist, classname, classname); + + constructor_token = FindClassFunction( constructor_token->next, classname, classname, indentlevel ); + ClassChecking_VarList_Initialize(constructor_token, varlist, classname); } // Delete the varlist.. diff --git a/tests.cpp b/tests.cpp index 36e221487..a270af360 100644 --- a/tests.cpp +++ b/tests.cpp @@ -31,18 +31,33 @@ static void memleak_in_class(); int main() { + // Provide a dummy filename for the error messages Files.push_back( std::string("test.cpp") ); + + // Check that the statement list is created correctly internal_statementlist(); + + // Check that buffer overruns are detected buffer_overrun(); + + // Test the constructor-checks constructors(); + + // Test the class operator= checking operator_eq(); + + // Test that memory leaks in a function are detected memleak_in_function(); + + // Test that memory leaks in a class are detected memleak_in_class(); + std::cout << "Success Rate: " << SuccessCount << " / " << (SuccessCount + FailCount) << std::endl; + return 0; } //--------------------------------------------------------------------------- @@ -350,6 +365,23 @@ static void buffer_overrun() "[test.cpp:15]: A string with unknown length is copied to buffer.\n"; check( CheckBufferOverrun, __LINE__, test7, err7 ); + + + // TODO + /* + const char test8[] = "class Fred\n" + "{\n" + "private:\n" + " char str[10];\n" + "public:\n" + " Fred();\n" + "};\n" + "Fred::Fred()\n" + "{\n" + " str[10] = 0;\n" + "}\n"; + check( CheckBufferOverrun, __LINE__, test8, "[test.cpp:5]: Array index out of bounds\n" ); + */ } //--------------------------------------------------------------------------- @@ -360,58 +392,58 @@ static void constructors() // Test3: Uninitialized variable // Test4: multiple constructors, uninitialized variable - const char test1[] = "class clKalle\n" + const char test1[] = "class Fred\n" "{\n" "public:\n" " int i;\n" "};\n"; - check( CheckConstructors, __LINE__, test1, "[test.cpp:1] The class 'clKalle' has no constructor\n" ); + check( CheckConstructors, __LINE__, test1, "[test.cpp:1] The class 'Fred' has no constructor\n" ); - const char test2[] = "class clKalle\n" + const char test2[] = "class Fred\n" "{\n" "public:\n" - " clKalle() { }\n" + " Fred() { }\n" " int i;\n" "};\n"; - check( CheckConstructors, __LINE__, test2, "" ); + check( CheckConstructors, __LINE__, test2, "[test.cpp:4] Uninitialized member variable 'Fred::i'\n" ); - const char test3[] = "class clKalle\n" + const char test3[] = "class Fred\n" "{\n" "public:\n" - " clKalle();\n" + " Fred();\n" " int i;\n" "};\n" - "clKalle::clKalle()\n" + "Fred::Fred()\n" "{ }\n"; - check( CheckConstructors, __LINE__, test3, "[test.cpp:8] Uninitialized member variable 'clKalle::i'\n" ); + check( CheckConstructors, __LINE__, test3, "[test.cpp:7] Uninitialized member variable 'Fred::i'\n" ); - const char test4[] = "class clKalle\n" + const char test4[] = "class Fred\n" "{\n" "public:\n" - " clKalle();\n" - " clKalle(int _i);\n" + " Fred();\n" + " Fred(int _i);\n" " int i;\n" "};\n" - "clKalle::clKalle()\n" + "Fred::Fred()\n" "{ }\n" - "clKalle::clKalle(int _i)\n" + "Fred::Fred(int _i)\n" "{\n" " i = _i;\n" "}\n"; - check( CheckConstructors, __LINE__, test4, "[test.cpp:9] Uninitialized member variable 'clKalle::i'\n" ); + check( CheckConstructors, __LINE__, test4, "[test.cpp:8] Uninitialized member variable 'Fred::i'\n" ); } //--------------------------------------------------------------------------- void operator_eq() { - const char test1[] = "class clKalle\n" + const char test1[] = "class Fred\n" "{\n" "public:\n" " void operator=(const int &value);\n" @@ -557,52 +589,82 @@ static void memleak_in_class() { - const char test1[] = "class clKalle\n" + const char test1[] = "class Fred\n" "{\n" "private:\n" " char *str1;\n" " char *str2;\n" "public:\n" - " clKalle();\n" - " ~clKalle();\n" + " Fred();\n" + " ~Fred();\n" "};\n" "\n" - "clKalle::clKalle()\n" + "Fred::Fred()\n" "{\n" " str1 = new char[10];\n" " str2 = new char[10];\n" "}\n" "\n" - "clKalle::~clKalle()\n" + "Fred::~Fred()\n" "{\n" " delete [] str2;\n" "}\n"; - check( CheckMemoryLeak, __LINE__, test1, "Memory leak for 'clKalle::str1'\n" ); + check( CheckMemoryLeak, __LINE__, test1, "Memory leak for 'Fred::str1'\n" ); - const char test2[] = "class clKalle\n" + const char test2[] = "class Fred\n" "{\n" "private:\n" " char *str1;\n" "public:\n" - " clKalle();\n" - " ~clKalle();\n" + " Fred();\n" + " ~Fred();\n" "};\n" "\n" - "clKalle::clKalle()\n" + "Fred::Fred()\n" "{\n" " str1 = new char[10];\n" "}\n" "\n" - "clKalle::~clKalle()\n" + "Fred::~Fred()\n" "{\n" " free(str1);\n" "}\n"; - check( CheckMemoryLeak, __LINE__, test2, "[test.cpp:17]: Mismatching deallocation for 'clKalle::str1'\n" ); + check( CheckMemoryLeak, __LINE__, test2, "[test.cpp:17]: Mismatching deallocation for 'Fred::str1'\n" ); + + + + + const char test3[] = "class Fred\n" + "{\n" + "private:\n" + " char *str;\n" + "public:\n" + " Fred();\n" + " ~Fred();\n" + " void SetStr(const char s[]);" + "};\n" + "\n" + "Fred::Fred()\n" + "{\n" + " str = NULL;\n" + "}\n" + "\n" + "Fred::~Fred()\n" + "{\n" + " free(str1);\n" + "}\n" + "\n" + "void Fred::SetStr(const char s[])\n" + "{\n" + " str = strdup(s);\n" + "}\n"; + + check( CheckMemoryLeak, __LINE__, test3, "Memory leak for 'Fred::str'\n" );