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");
|
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.
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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"
|
||||||
|
|
Loading…
Reference in New Issue