Fixed #1757 (Undefined Behavior: Shift too many bits)

This commit is contained in:
Daniel Marjamäki 2014-09-09 07:24:59 +02:00
parent f7824bfd00
commit f111a89639
3 changed files with 75 additions and 1 deletions

View File

@ -2663,6 +2663,57 @@ void CheckOther::negativeBitwiseShiftError(const Token *tok)
reportError(tok, Severity::error, "shiftNegative", "Shifting by a negative value is undefined behaviour"); reportError(tok, Severity::error, "shiftNegative", "Shifting by a negative value is undefined behaviour");
} }
//---------------------------------------------------------------------------
// Checking for shift by too many bits
//---------------------------------------------------------------------------
void CheckOther::checkTooBigBitwiseShift()
{
// unknown sizeof(int) => can't run this checker
if (_settings->platformType == Settings::Unspecified)
return;
const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase();
const std::size_t functions = symbolDatabase->functionScopes.size();
for (std::size_t i = 0; i < functions; ++i) {
const Scope * scope = symbolDatabase->functionScopes[i];
for (const Token* tok = scope->classStart->next(); tok != scope->classEnd; tok = tok->next()) {
if (tok->str() != "<<" && tok->str() != ">>")
continue;
if (!tok->astOperand1() || !tok->astOperand2())
continue;
// get number of bits of lhs
const Variable *var = tok->astOperand1()->variable();
if (!var)
continue;
int lhsbits = 0;
for (const Token *type = var->typeStartToken(); type; type = type->next()) {
if (Token::Match(type,"char|short|int") && !type->isLong()) {
lhsbits = _settings->sizeof_int * 8;
break;
}
if (type == var->typeEndToken())
break;
}
if (lhsbits == 0)
continue;
// Get biggest rhs value. preferably a value which doesn't have 'condition'.
const ValueFlow::Value *value = tok->astOperand2()->getValueGE(lhsbits, _settings);
if (value)
tooBigBitwiseShiftError(tok, lhsbits, value->intvalue);
}
}
}
void CheckOther::tooBigBitwiseShiftError(const Token *tok, int lhsbits, MathLib::bigint rhsbits)
{
std::ostringstream errmsg;
errmsg << "Shifting " << lhsbits << "-bit value by " << rhsbits << " bits is undefined behaviour";
reportError(tok, Severity::error, "shiftTooManyBits", errmsg.str());
}
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
// Check for incompletely filled buffers. // Check for incompletely filled buffers.

View File

@ -102,6 +102,7 @@ public:
checkOther.checkDoubleFree(); checkOther.checkDoubleFree();
checkOther.checkRedundantCopy(); checkOther.checkRedundantCopy();
checkOther.checkNegativeBitwiseShift(); checkOther.checkNegativeBitwiseShift();
checkOther.checkTooBigBitwiseShift();
checkOther.checkSuspiciousEqualityComparison(); checkOther.checkSuspiciousEqualityComparison();
checkOther.checkComparisonFunctionIsAlwaysTrueOrFalse(); checkOther.checkComparisonFunctionIsAlwaysTrueOrFalse();
} }
@ -215,9 +216,12 @@ public:
/** @brief %Check for code creating redundant copies */ /** @brief %Check for code creating redundant copies */
void checkRedundantCopy(); void checkRedundantCopy();
/** @brief %Check for bitwise operation with negative right operand */ /** @brief %Check for bitwise shift with negative right operand */
void checkNegativeBitwiseShift(); void checkNegativeBitwiseShift();
/** @brief %Check for bitwise shift with too big right operand */
void checkTooBigBitwiseShift();
/** @brief %Check for buffers that are filled incompletely with memset and similar functions */ /** @brief %Check for buffers that are filled incompletely with memset and similar functions */
void checkIncompleteArrayFill(); void checkIncompleteArrayFill();
@ -286,6 +290,7 @@ private:
void SuspiciousSemicolonError(const Token *tok); void SuspiciousSemicolonError(const Token *tok);
void doubleCloseDirError(const Token *tok, const std::string &varname); void doubleCloseDirError(const Token *tok, const std::string &varname);
void negativeBitwiseShiftError(const Token *tok); void negativeBitwiseShiftError(const Token *tok);
void tooBigBitwiseShiftError(const Token *tok, int lhsbits, MathLib::bigint rhsbits);
void redundantCopyError(const Token *tok, const std::string &varname); void redundantCopyError(const Token *tok, const std::string &varname);
void incompleteArrayFillError(const Token* tok, const std::string& buffer, const std::string& function, bool boolean); void incompleteArrayFillError(const Token* tok, const std::string& buffer, const std::string& function, bool boolean);
void varFuncNullUBError(const Token *tok); void varFuncNullUBError(const Token *tok);
@ -304,6 +309,7 @@ private:
c.doubleFreeError(0, "varname"); c.doubleFreeError(0, "varname");
c.invalidPointerCastError(0, "float", "double", false); c.invalidPointerCastError(0, "float", "double", false);
c.negativeBitwiseShiftError(0); c.negativeBitwiseShiftError(0);
c.tooBigBitwiseShiftError(0, 32, 64);
c.checkPipeParameterSizeError(0, "varname", "dimension"); c.checkPipeParameterSizeError(0, "varname", "dimension");
//performance //performance
@ -366,6 +372,7 @@ private:
"* provide wrong dimensioned array to pipe() system command (--std=posix)\n" "* provide wrong dimensioned array to pipe() system command (--std=posix)\n"
"* cast the return values of getc(),fgetc() and getchar() to character and compare it to EOF\n" "* cast the return values of getc(),fgetc() and getchar() to character and compare it to EOF\n"
"* invalid input values for functions\n" "* invalid input values for functions\n"
"* bitwise shift by too many bits\n"
// warning // warning
"* either division by zero or useless condition\n" "* either division by zero or useless condition\n"

View File

@ -148,6 +148,7 @@ private:
TEST_CASE(checkRedundantCopy); TEST_CASE(checkRedundantCopy);
TEST_CASE(checkNegativeShift); TEST_CASE(checkNegativeShift);
TEST_CASE(checkTooBigShift);
TEST_CASE(incompleteArrayFill); TEST_CASE(incompleteArrayFill);
@ -5384,6 +5385,21 @@ private:
ASSERT_EQUALS("", errout.str()); ASSERT_EQUALS("", errout.str());
} }
void checkTooBigShift() {
Settings settings;
settings.platform(Settings::Unix32);
check("int foo(int x) {\n"
" return x << 32;\n"
"}","test.cpp",false,false,false,true,&settings);
ASSERT_EQUALS("[test.cpp:2]: (error) Shifting 32-bit value by 32 bits is undefined behaviour\n", errout.str());
check("int foo(int x) {\n"
" return x << 2;\n"
"}","test.cpp",false,false,false,true,&settings);
ASSERT_EQUALS("", errout.str());
}
void incompleteArrayFill() { void incompleteArrayFill() {
check("void f() {\n" check("void f() {\n"
" int a[5];\n" " int a[5];\n"