From 08b3b2ab633b16b117603a0ebb286c42ef266880 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Wed, 20 Feb 2008 18:20:59 +0000 Subject: [PATCH] CheckUnsignedDivision: Added check. Not very accurate yet. --- CheckOther.cpp | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ CheckOther.h | 3 +++ main.cpp | 6 ++++++ tests.cpp | 21 ++++++++++++++++++++- tokenize.cpp | 14 ++++++++++---- 5 files changed, 88 insertions(+), 5 deletions(-) diff --git a/CheckOther.cpp b/CheckOther.cpp index dbcb8ac1f..e7bba8825 100644 --- a/CheckOther.cpp +++ b/CheckOther.cpp @@ -519,5 +519,54 @@ void CheckCaseWithoutBreak() } } +//--------------------------------------------------------------------------- + + + +//--------------------------------------------------------------------------- +// Check for case without break +//--------------------------------------------------------------------------- + +void CheckUnsignedDivision() +{ + const char *pattern_declvar[] = { "unsigned", "int", "", NULL }; + TOKEN *declvar = findtoken(tokens, pattern_declvar); + while ( declvar ) + { + const char *varname = getstr( declvar, 2 ); + if ( ! IsName(varname) ) + { + declvar = findtoken( declvar->next, pattern_declvar ); + continue; + } + + const char *pattern_div1[] = { "/", "", NULL }; + pattern_div1[1] = varname; + TOKEN *tokdiv = findtoken(declvar, pattern_div1); + while ( tokdiv ) + { + std::ostringstream ostr; + ostr << FileLine(tokdiv) << ": If the result is negative it will be wrong because an operand is unsigned."; + ReportErr(ostr.str()); + tokdiv = findtoken(tokdiv->next, pattern_div1); + } + + const char *pattern_div2[] = { "", "", "/", NULL }; + pattern_div2[1] = varname; + tokdiv = findtoken(declvar, pattern_div2); + while ( tokdiv ) + { + if ( tokdiv->str[0] != ')' ) // The ')' may indicate a cast + { + std::ostringstream ostr; + ostr << FileLine(tokdiv) << ": If the result is negative it will be wrong because an operand is unsigned."; + ReportErr(ostr.str()); + } + tokdiv = findtoken(tokdiv->next, pattern_div2); + } + + declvar = findtoken(declvar->next, pattern_declvar); + } +} diff --git a/CheckOther.h b/CheckOther.h index bdecec962..5beb5a4cb 100644 --- a/CheckOther.h +++ b/CheckOther.h @@ -34,6 +34,9 @@ void WarningStrTok(); // Check for a 'case' without a 'break' void CheckCaseWithoutBreak(); +// Check for unsigned division that might create bad results +void CheckUnsignedDivision(); + //--------------------------------------------------------------------------- #endif diff --git a/main.cpp b/main.cpp index e16ed5580..4b2ff5f44 100644 --- a/main.cpp +++ b/main.cpp @@ -114,6 +114,12 @@ static void CppCheck(const char FileName[]) CheckMemset(); + // Check for unwanted unsigned division + // Not accurate yet. Very important to run it before 'SimplifyTokenList' + if ( ShowAll ) + CheckUnsignedDivision(); + + // Including header which is not needed if ( CheckCodingStyle ) WarningIncludeHeader(); diff --git a/tests.cpp b/tests.cpp index a270af360..e616da9df 100644 --- a/tests.cpp +++ b/tests.cpp @@ -10,6 +10,7 @@ #include "CheckBufferOverrun.h" #include "CheckClass.h" #include "CheckMemoryLeak.h" +#include "CheckOther.h" #include #include @@ -27,6 +28,7 @@ static void constructors(); static void operator_eq(); static void memleak_in_function(); static void memleak_in_class(); +static void division(); //--------------------------------------------------------------------------- int main() @@ -52,6 +54,9 @@ int main() // Test that memory leaks in a class are detected memleak_in_class(); + // Check for dangerous division.. such as "svar / uvar". Treating "svar" as unsigned data is not good + division(); + std::cout << "Success Rate: " << SuccessCount << " / " @@ -71,7 +76,8 @@ static void check(void (chk)(), tokens = tokens_back = NULL; std::istringstream istr(code); TokenizeCode( istr ); - SimplifyTokenList(); + if ( chk != CheckUnsignedDivision ) + SimplifyTokenList(); // Check for buffer overruns.. errout.str(""); @@ -671,3 +677,16 @@ static void memleak_in_class() } //--------------------------------------------------------------------------- +static void division() +{ + + const char test1[] = "void f()\n" + "{\n" + " unsigned int uvar = 2;\n" + " return -2 / uvar;\n" + "}\n"; + check( CheckUnsignedDivision, __LINE__, test1, "[test.cpp:4]: If the result is negative it will be wrong because an operand is unsigned.\n" ); + + +} +//--------------------------------------------------------------------------- diff --git a/tokenize.cpp b/tokenize.cpp index afa7dd260..f9414dcdf 100644 --- a/tokenize.cpp +++ b/tokenize.cpp @@ -109,10 +109,6 @@ static void addtoken(const char str[], const unsigned int lineno, const unsigned if (str[0] == 0) return; - // The keyword 'unsigned' can be skipped for now. - if (strcmp(str,"unsigned")==0) - return; - // Replace hexadecimal value with decimal char str2[50]; memset(str2, 0, sizeof(str2)); @@ -539,6 +535,16 @@ void TokenizeCode(std::istream &code, const unsigned int FileIndex) void SimplifyTokenList() { + + // Remove the keyword 'unsigned' + for ( TOKEN *tok = tokens; tok; tok = tok->next ) + { + if (tok->next && strcmp(tok->next->str,"unsigned")==0) + { + DeleteNextToken( tok ); + } + } + // Replace constants.. for (TOKEN *tok = tokens; tok; tok = tok->next) {