Fix #4233 FN: Bitwise operation with bool and int (#4266)

* Fix #4233 FN: Bitwise operation with bool and int

* Format
This commit is contained in:
chrchr-github 2022-07-11 22:58:37 +02:00 committed by GitHub
parent 8fc75402a1
commit c5dcd49dae
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 39 additions and 9 deletions

View File

@ -99,30 +99,43 @@ void CheckBool::checkBitwiseOnBoolean()
const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase(); const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
for (const Scope * scope : symbolDatabase->functionScopes) { for (const Scope * scope : symbolDatabase->functionScopes) {
for (const Token* tok = scope->bodyStart->next(); tok != scope->bodyEnd; tok = tok->next()) { for (const Token* tok = scope->bodyStart->next(); tok != scope->bodyEnd; tok = tok->next()) {
if (tok->isBinaryOp() && (tok->str() == "&" || tok->str() == "|")) { if (tok->isBinaryOp()) {
if (!(astIsBool(tok->astOperand1()) || astIsBool(tok->astOperand2()))) bool isCompound{};
if (tok->str() == "&" || tok->str() == "|")
isCompound = false;
else if (tok->str() == "&=" || tok->str() == "|=")
isCompound = true;
else
continue; continue;
if (tok->str() == "|" && !isConvertedToBool(tok) && !(astIsBool(tok->astOperand1()) && astIsBool(tok->astOperand2()))) const bool isBoolOp1 = astIsBool(tok->astOperand1());
const bool isBoolOp2 = astIsBool(tok->astOperand2());
if (!(isBoolOp1 || isBoolOp2))
continue;
if (isCompound && !isBoolOp1)
continue;
if (tok->str() == "|" && !isConvertedToBool(tok) && !(isBoolOp1 && isBoolOp2))
continue; continue;
// first operand will always be evaluated // first operand will always be evaluated
if (!isConstExpression(tok->astOperand2(), mSettings->library, true, mTokenizer->isCPP())) if (!isConstExpression(tok->astOperand2(), mSettings->library, true, mTokenizer->isCPP()))
continue; continue;
if (tok->astOperand2()->variable() && tok->astOperand2()->variable()->nameToken() == tok->astOperand2()) if (tok->astOperand2()->variable() && tok->astOperand2()->variable()->nameToken() == tok->astOperand2())
continue; continue;
const std::string expression = astIsBool(tok->astOperand1()) ? tok->astOperand1()->expressionString() const std::string expression = (isBoolOp1 ? tok->astOperand1() : tok->astOperand2())->expressionString();
: tok->astOperand2()->expressionString(); bitwiseOnBooleanError(tok, expression, tok->str() == "&" ? "&&" : "||", isCompound);
bitwiseOnBooleanError(tok, expression, tok->str() == "&" ? "&&" : "||");
} }
} }
} }
} }
void CheckBool::bitwiseOnBooleanError(const Token* tok, const std::string& expression, const std::string& op) void CheckBool::bitwiseOnBooleanError(const Token* tok, const std::string& expression, const std::string& op, bool isCompound)
{ {
std::string msg = "Boolean expression '" + expression + "' is used in bitwise operation.";
if (!isCompound)
msg += " Did you mean '" + op + "'?";
reportError(tok, reportError(tok,
Severity::style, Severity::style,
"bitwiseOnBoolean", "bitwiseOnBoolean",
"Boolean expression '" + expression + "' is used in bitwise operation. Did you mean '" + op + "'?", msg,
CWE398, CWE398,
Certainty::inconclusive); Certainty::inconclusive);
} }

View File

@ -104,7 +104,7 @@ private:
void comparisonOfBoolWithInvalidComparator(const Token *tok, const std::string &expression); void comparisonOfBoolWithInvalidComparator(const Token *tok, const std::string &expression);
void assignBoolToPointerError(const Token *tok); void assignBoolToPointerError(const Token *tok);
void assignBoolToFloatError(const Token *tok); void assignBoolToFloatError(const Token *tok);
void bitwiseOnBooleanError(const Token* tok, const std::string& expression, const std::string& op); void bitwiseOnBooleanError(const Token* tok, const std::string& expression, const std::string& op, bool isCompound = false);
void comparisonOfBoolExpressionWithIntError(const Token *tok, bool not0or1); void comparisonOfBoolExpressionWithIntError(const Token *tok, bool not0or1);
void pointerArithBoolError(const Token *tok); void pointerArithBoolError(const Token *tok);
void returnValueBoolError(const Token *tok); void returnValueBoolError(const Token *tok);

View File

@ -932,6 +932,23 @@ private:
" return b | g() | c;\n" " return b | g() | c;\n"
"}\n"); "}\n");
ASSERT_EQUALS("[test.cpp:3]: (style, inconclusive) Boolean expression 'c' is used in bitwise operation. Did you mean '||'?\n", errout.str()); ASSERT_EQUALS("[test.cpp:3]: (style, inconclusive) Boolean expression 'c' is used in bitwise operation. Did you mean '||'?\n", errout.str());
check("void f(int i) {\n" // #4233
" bool b = true, c = false;\n"
" b &= i;\n"
" c |= i;\n"
" if (b || c) {}\n"
"}\n");
ASSERT_EQUALS("[test.cpp:3]: (style, inconclusive) Boolean expression 'b' is used in bitwise operation.\n"
"[test.cpp:4]: (style, inconclusive) Boolean expression 'c' is used in bitwise operation.\n",
errout.str());
check("void f(int i, int j, bool b) {\n"
" i &= b;\n"
" j |= b;\n"
" if (b || c) {}\n"
"}\n");
ASSERT_EQUALS("", errout.str());
} }
void incrementBoolean() { void incrementBoolean() {