Fixed #2866 (Detect sign extension bugs)

This commit is contained in:
Daniel Marjamäki 2011-07-05 18:41:27 +02:00
parent 657b003dc8
commit 8cd2c3115e
2 changed files with 61 additions and 14 deletions

View File

@ -2761,15 +2761,22 @@ void CheckOther::checkCharVariable()
for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next())
{
// Declaring the variable..
if (Token::Match(tok, "[{};(,] char %var% [;=,)]"))
if (Token::Match(tok, "[{};(,] const| char *| %var% [;=,)]") ||
Token::Match(tok, "[{};(,] const| char %var% ["))
{
// goto 'char' token
tok = tok->next();
if (tok->str() == "const")
tok = tok->next();
// Check for unsigned char
if (tok->tokAt(1)->isUnsigned())
if (tok->isUnsigned())
continue;
// Set tok to point to the variable name
tok = tok->tokAt(2);
if (tok->str() == "char")
tok = tok->next();
const bool isPointer(tok->str() == "*" || tok->strAt(1) == "[");
if (tok->str() == "*")
tok = tok->next();
// Check usage of char variable..
@ -2786,9 +2793,6 @@ void CheckOther::checkCharVariable()
break;
}
else if (tok2->str() == "return")
continue;
std::string temp = "%var% [ " + tok->str() + " ]";
if ((tok2->str() != ".") && Token::Match(tok2->next(), temp.c_str()))
{
@ -2803,7 +2807,7 @@ void CheckOther::checkCharVariable()
continue;
// it's ok with a bitwise and where the other operand is 0xff or less..
if (std::string(tok2->strAt(4)) == "&")
if (tok2->strAt(4) == "&")
{
if (tok2->tokAt(3)->isNumber() && MathLib::isGreater("0x100", tok2->strAt(3)))
continue;
@ -2819,6 +2823,21 @@ void CheckOther::checkCharVariable()
charBitOpError(tok2);
break;
}
if (isPointer && Token::Match(tok2, "[;{}] %var% = %any% [&|] ( * %varid% ) ;", tok->varId()))
{
// it's ok with a bitwise and where the other operand is 0xff or less..
if (tok2->strAt(4) == "&" && tok2->tokAt(3)->isNumber() && MathLib::isGreater("0x100", tok2->strAt(3)))
continue;
// is the result stored in a short|int|long?
if (!Token::findmatch(_tokenizer->tokens(), "short|int|long %varid%", tok2->next()->varId()))
continue;
// This is an error..
charBitOpError(tok2);
break;
}
}
}
}
@ -3477,12 +3496,30 @@ void CheckOther::constStatementError(const Token *tok, const std::string &type)
void CheckOther::charArrayIndexError(const Token *tok)
{
reportError(tok, Severity::warning, "charArrayIndex", "Warning - using char variable as array index");
reportError(tok,
Severity::warning,
"charArrayIndex",
"When using a char variable as array index, sign extension will mean buffer overflow.\n"
"When using a char variable as array index, sign extension will cause buffer overflows. For example:\n"
" char c = 0x80;\n"
" char buf[512];\n"
" buf[c] = 13; // buffer overflow, index must be a value between 0 and 511.\n"
" printf(\"%i\", buf[0x80]);\n"
"There is a big chance that the value that is printed won't be 13.");
}
void CheckOther::charBitOpError(const Token *tok)
{
reportError(tok, Severity::warning, "charBitOp", "Warning - using char variable in bit operation");
reportError(tok,
Severity::warning,
"charBitOp",
"When using char variables in bit operations, sign extension can generate unexpected results.\n"
"When using char variables in bit operations, sign extension can generate unexpected results. For example:\n"
" char c = 0x80;\n"
" int i = 0 | c;\n"
" if (i & 0x8000)\n"
" printf(\"not expected\");\n"
"The 'not expected' will be printed on the screen.");
}
void CheckOther::variableScopeError(const Token *tok, const std::string &varname)

View File

@ -41,6 +41,7 @@ private:
TEST_CASE(return1);
TEST_CASE(assignChar);
TEST_CASE(and03);
TEST_CASE(pointer);
}
void check(const char code[])
@ -76,20 +77,20 @@ private:
" char ch = 0x80;\n"
" buf[ch] = 0;\n"
"}\n");
ASSERT_EQUALS("[test.cpp:4]: (warning) Warning - using char variable as array index\n", errout.str());
ASSERT_EQUALS("[test.cpp:4]: (warning) When using a char variable as array index, sign extension will mean buffer overflow.\n", errout.str());
check("void foo()\n"
"{\n"
" signed char ch = 0x80;\n"
" buf[ch] = 0;\n"
"}\n");
ASSERT_EQUALS("[test.cpp:4]: (warning) Warning - using char variable as array index\n", errout.str());
ASSERT_EQUALS("[test.cpp:4]: (warning) When using a char variable as array index, sign extension will mean buffer overflow.\n", errout.str());
check("void foo(char ch)\n"
"{\n"
" buf[ch] = 0;\n"
"}\n");
ASSERT_EQUALS("[test.cpp:3]: (warning) Warning - using char variable as array index\n", errout.str());
ASSERT_EQUALS("[test.cpp:3]: (warning) When using a char variable as array index, sign extension will mean buffer overflow.\n", errout.str());
}
@ -101,7 +102,7 @@ private:
" char ch;\n"
" result = a | ch;\n"
"}\n");
ASSERT_EQUALS("[test.cpp:4]: (warning) Warning - using char variable in bit operation\n", errout.str());
ASSERT_EQUALS("[test.cpp:4]: (warning) When using char variables in bit operations, sign extension can generate unexpected results.\n", errout.str());
}
void bitop2()
@ -145,6 +146,15 @@ private:
ASSERT_EQUALS("", errout.str());
}
void pointer()
{
check("void f(char *p) {\n"
" int ret = 0;\n"
" ret |= *p;\n"
" return ret;\n"
"}");
ASSERT_EQUALS("[test.cpp:2]: (warning) When using char variables in bit operations, sign extension can generate unexpected results.\n", errout.str());
}
};
REGISTER_TEST(TestCharVar)