CheckUnsignedDivision: Added check. Not very accurate yet.
This commit is contained in:
parent
a40c1e9eb7
commit
08b3b2ab63
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
6
main.cpp
6
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();
|
||||
|
|
19
tests.cpp
19
tests.cpp
|
@ -10,6 +10,7 @@
|
|||
#include "CheckBufferOverrun.h"
|
||||
#include "CheckClass.h"
|
||||
#include "CheckMemoryLeak.h"
|
||||
#include "CheckOther.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
@ -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,6 +76,7 @@ static void check(void (chk)(),
|
|||
tokens = tokens_back = NULL;
|
||||
std::istringstream istr(code);
|
||||
TokenizeCode( istr );
|
||||
if ( chk != CheckUnsignedDivision )
|
||||
SimplifyTokenList();
|
||||
|
||||
// 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" );
|
||||
|
||||
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
|
|
14
tokenize.cpp
14
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)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue