CheckUnsignedDivision: Added check. Not very accurate yet.

This commit is contained in:
Daniel Marjamäki 2008-02-20 18:20:59 +00:00
parent a40c1e9eb7
commit 08b3b2ab63
5 changed files with 88 additions and 5 deletions

View File

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

View File

@ -34,6 +34,9 @@ void WarningStrTok();
// Check for a 'case' without a 'break' // Check for a 'case' without a 'break'
void CheckCaseWithoutBreak(); void CheckCaseWithoutBreak();
// Check for unsigned division that might create bad results
void CheckUnsignedDivision();
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
#endif #endif

View File

@ -114,6 +114,12 @@ static void CppCheck(const char FileName[])
CheckMemset(); 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 // Including header which is not needed
if ( CheckCodingStyle ) if ( CheckCodingStyle )
WarningIncludeHeader(); WarningIncludeHeader();

View File

@ -10,6 +10,7 @@
#include "CheckBufferOverrun.h" #include "CheckBufferOverrun.h"
#include "CheckClass.h" #include "CheckClass.h"
#include "CheckMemoryLeak.h" #include "CheckMemoryLeak.h"
#include "CheckOther.h"
#include <iostream> #include <iostream>
#include <sstream> #include <sstream>
@ -27,6 +28,7 @@ static void constructors();
static void operator_eq(); static void operator_eq();
static void memleak_in_function(); static void memleak_in_function();
static void memleak_in_class(); static void memleak_in_class();
static void division();
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
int main() int main()
@ -52,6 +54,9 @@ int main()
// Test that memory leaks in a class are detected // Test that memory leaks in a class are detected
memleak_in_class(); memleak_in_class();
// Check for dangerous division.. such as "svar / uvar". Treating "svar" as unsigned data is not good
division();
std::cout << "Success Rate: " std::cout << "Success Rate: "
<< SuccessCount << SuccessCount
<< " / " << " / "
@ -71,6 +76,7 @@ static void check(void (chk)(),
tokens = tokens_back = NULL; tokens = tokens_back = NULL;
std::istringstream istr(code); std::istringstream istr(code);
TokenizeCode( istr ); TokenizeCode( istr );
if ( chk != CheckUnsignedDivision )
SimplifyTokenList(); SimplifyTokenList();
// Check for buffer overruns.. // Check for buffer overruns..
@ -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" );
}
//---------------------------------------------------------------------------

View File

@ -109,10 +109,6 @@ static void addtoken(const char str[], const unsigned int lineno, const unsigned
if (str[0] == 0) if (str[0] == 0)
return; return;
// The keyword 'unsigned' can be skipped for now.
if (strcmp(str,"unsigned")==0)
return;
// Replace hexadecimal value with decimal // Replace hexadecimal value with decimal
char str2[50]; char str2[50];
memset(str2, 0, sizeof(str2)); memset(str2, 0, sizeof(str2));
@ -539,6 +535,16 @@ void TokenizeCode(std::istream &code, const unsigned int FileIndex)
void SimplifyTokenList() 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.. // Replace constants..
for (TOKEN *tok = tokens; tok; tok = tok->next) for (TOKEN *tok = tokens; tok; tok = tok->next)
{ {