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'
|
// Check for a 'case' without a 'break'
|
||||||
void CheckCaseWithoutBreak();
|
void CheckCaseWithoutBreak();
|
||||||
|
|
||||||
|
// Check for unsigned division that might create bad results
|
||||||
|
void CheckUnsignedDivision();
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
6
main.cpp
6
main.cpp
|
@ -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();
|
||||||
|
|
19
tests.cpp
19
tests.cpp
|
@ -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" );
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
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)
|
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)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue