Fixed #1757 (Undefined Behavior: Shift too many bits)
This commit is contained in:
parent
f7824bfd00
commit
f111a89639
|
@ -2663,6 +2663,57 @@ void CheckOther::negativeBitwiseShiftError(const Token *tok)
|
|||
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.
|
||||
|
|
|
@ -102,6 +102,7 @@ public:
|
|||
checkOther.checkDoubleFree();
|
||||
checkOther.checkRedundantCopy();
|
||||
checkOther.checkNegativeBitwiseShift();
|
||||
checkOther.checkTooBigBitwiseShift();
|
||||
checkOther.checkSuspiciousEqualityComparison();
|
||||
checkOther.checkComparisonFunctionIsAlwaysTrueOrFalse();
|
||||
}
|
||||
|
@ -215,9 +216,12 @@ public:
|
|||
/** @brief %Check for code creating redundant copies */
|
||||
void checkRedundantCopy();
|
||||
|
||||
/** @brief %Check for bitwise operation with negative right operand */
|
||||
/** @brief %Check for bitwise shift with negative right operand */
|
||||
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 */
|
||||
void checkIncompleteArrayFill();
|
||||
|
||||
|
@ -286,6 +290,7 @@ private:
|
|||
void SuspiciousSemicolonError(const Token *tok);
|
||||
void doubleCloseDirError(const Token *tok, const std::string &varname);
|
||||
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 incompleteArrayFillError(const Token* tok, const std::string& buffer, const std::string& function, bool boolean);
|
||||
void varFuncNullUBError(const Token *tok);
|
||||
|
@ -304,6 +309,7 @@ private:
|
|||
c.doubleFreeError(0, "varname");
|
||||
c.invalidPointerCastError(0, "float", "double", false);
|
||||
c.negativeBitwiseShiftError(0);
|
||||
c.tooBigBitwiseShiftError(0, 32, 64);
|
||||
c.checkPipeParameterSizeError(0, "varname", "dimension");
|
||||
|
||||
//performance
|
||||
|
@ -366,6 +372,7 @@ private:
|
|||
"* 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"
|
||||
"* invalid input values for functions\n"
|
||||
"* bitwise shift by too many bits\n"
|
||||
|
||||
// warning
|
||||
"* either division by zero or useless condition\n"
|
||||
|
|
|
@ -148,6 +148,7 @@ private:
|
|||
TEST_CASE(checkRedundantCopy);
|
||||
|
||||
TEST_CASE(checkNegativeShift);
|
||||
TEST_CASE(checkTooBigShift);
|
||||
|
||||
TEST_CASE(incompleteArrayFill);
|
||||
|
||||
|
@ -5384,6 +5385,21 @@ private:
|
|||
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() {
|
||||
check("void f() {\n"
|
||||
" int a[5];\n"
|
||||
|
|
Loading…
Reference in New Issue