misra; implement rule 14.3
This commit is contained in:
parent
2abe07f279
commit
cbb07b6247
|
@ -1757,3 +1757,74 @@ void CheckCondition::assignmentInCondition(const Token *eq)
|
||||||
Certainty::normal);
|
Certainty::normal);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CheckCondition::checkCompareValueOutOfTypeRange()
|
||||||
|
{
|
||||||
|
if (!mSettings->severity.isEnabled(Severity::style))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (mSettings->platformType == cppcheck::Platform::PlatformType::Native ||
|
||||||
|
mSettings->platformType == cppcheck::Platform::PlatformType::Unspecified)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
|
||||||
|
for (const Scope * scope : symbolDatabase->functionScopes) {
|
||||||
|
for (const Token* tok = scope->bodyStart; tok != scope->bodyEnd; tok = tok->next()) {
|
||||||
|
if (!tok->isComparisonOp() || !tok->isBinaryOp())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (int i = 0; i < 2; ++i) {
|
||||||
|
const Token * const valueTok = (i == 0) ? tok->astOperand1() : tok->astOperand2();
|
||||||
|
const Token * const typeTok = valueTok->astSibling();
|
||||||
|
if (!valueTok->hasKnownIntValue() || !typeTok->valueType() || typeTok->valueType()->pointer)
|
||||||
|
continue;
|
||||||
|
if (valueTok->getKnownIntValue() < 0 && valueTok->valueType() && valueTok->valueType()->sign != ValueType::Sign::SIGNED)
|
||||||
|
continue;
|
||||||
|
int bits = 0;
|
||||||
|
switch (typeTok->valueType()->type) {
|
||||||
|
case ValueType::Type::BOOL:
|
||||||
|
bits = 1;
|
||||||
|
break;
|
||||||
|
case ValueType::Type::CHAR:
|
||||||
|
bits = mSettings->char_bit;
|
||||||
|
break;
|
||||||
|
case ValueType::Type::SHORT:
|
||||||
|
bits = mSettings->short_bit;
|
||||||
|
break;
|
||||||
|
case ValueType::Type::INT:
|
||||||
|
bits = mSettings->int_bit;
|
||||||
|
break;
|
||||||
|
case ValueType::Type::LONG:
|
||||||
|
bits = mSettings->long_bit;
|
||||||
|
break;
|
||||||
|
case ValueType::Type::LONGLONG:
|
||||||
|
bits = mSettings->long_long_bit;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
if (bits == 0 || bits >= 64)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const auto typeMinValue = (typeTok->valueType()->sign == ValueType::Sign::SIGNED) ? (-(1LL << (bits-1))) : 0;
|
||||||
|
const auto unsignedTypeMaxValue = (1LL << (bits-1)) - 1LL;
|
||||||
|
const auto typeMaxValue = (typeTok->valueType()->sign == ValueType::Sign::SIGNED) ? (unsignedTypeMaxValue / 2) : unsignedTypeMaxValue;
|
||||||
|
|
||||||
|
if (valueTok->getKnownIntValue() < typeMinValue)
|
||||||
|
compareValueOutOfTypeRangeError(valueTok, typeTok->valueType()->str(), valueTok->getKnownIntValue());
|
||||||
|
else if (valueTok->getKnownIntValue() > typeMaxValue)
|
||||||
|
compareValueOutOfTypeRangeError(valueTok, typeTok->valueType()->str(), valueTok->getKnownIntValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CheckCondition::compareValueOutOfTypeRangeError(const Token *comparison, const std::string &type, long long value)
|
||||||
|
{
|
||||||
|
reportError(
|
||||||
|
comparison,
|
||||||
|
Severity::style,
|
||||||
|
"compareValueOutOfTypeRangeError",
|
||||||
|
"Comparing expression of type '" + type + "' against value " + std::to_string(value) + ". Condition is always true/false.",
|
||||||
|
CWE398,
|
||||||
|
Certainty::normal);
|
||||||
|
}
|
||||||
|
|
|
@ -71,6 +71,7 @@ public:
|
||||||
checkCondition.comparison();
|
checkCondition.comparison();
|
||||||
checkCondition.checkModuloAlwaysTrueFalse();
|
checkCondition.checkModuloAlwaysTrueFalse();
|
||||||
checkCondition.checkAssignmentInCondition();
|
checkCondition.checkAssignmentInCondition();
|
||||||
|
checkCondition.checkCompareValueOutOfTypeRange();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** mismatching assignment / comparison */
|
/** mismatching assignment / comparison */
|
||||||
|
@ -167,6 +168,9 @@ private:
|
||||||
|
|
||||||
void assignmentInCondition(const Token *eq);
|
void assignmentInCondition(const Token *eq);
|
||||||
|
|
||||||
|
void checkCompareValueOutOfTypeRange();
|
||||||
|
void compareValueOutOfTypeRangeError(const Token *comparison, const std::string &type, long long value);
|
||||||
|
|
||||||
void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const OVERRIDE {
|
void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const OVERRIDE {
|
||||||
CheckCondition c(nullptr, settings, errorLogger);
|
CheckCondition c(nullptr, settings, errorLogger);
|
||||||
|
|
||||||
|
@ -190,6 +194,7 @@ private:
|
||||||
c.pointerAdditionResultNotNullError(nullptr, nullptr);
|
c.pointerAdditionResultNotNullError(nullptr, nullptr);
|
||||||
c.duplicateConditionalAssignError(nullptr, nullptr);
|
c.duplicateConditionalAssignError(nullptr, nullptr);
|
||||||
c.assignmentInCondition(nullptr);
|
c.assignmentInCondition(nullptr);
|
||||||
|
c.compareValueOutOfTypeRangeError(nullptr, "unsigned char", 256);
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string myName() {
|
static std::string myName() {
|
||||||
|
|
|
@ -38,6 +38,10 @@ private:
|
||||||
Settings settings1;
|
Settings settings1;
|
||||||
|
|
||||||
void run() OVERRIDE {
|
void run() OVERRIDE {
|
||||||
|
// known platform..
|
||||||
|
settings0.platform(cppcheck::Platform::PlatformType::Native);
|
||||||
|
settings1.platform(cppcheck::Platform::PlatformType::Native);
|
||||||
|
|
||||||
LOAD_LIB_2(settings0.library, "qt.cfg");
|
LOAD_LIB_2(settings0.library, "qt.cfg");
|
||||||
LOAD_LIB_2(settings0.library, "std.cfg");
|
LOAD_LIB_2(settings0.library, "std.cfg");
|
||||||
|
|
||||||
|
@ -123,14 +127,14 @@ private:
|
||||||
TEST_CASE(duplicateConditionalAssign);
|
TEST_CASE(duplicateConditionalAssign);
|
||||||
|
|
||||||
TEST_CASE(checkAssignmentInCondition);
|
TEST_CASE(checkAssignmentInCondition);
|
||||||
|
|
||||||
|
TEST_CASE(compareOutOfTypeRange);
|
||||||
}
|
}
|
||||||
|
|
||||||
void check(const char code[], const char* filename = "test.cpp", bool inconclusive = false) {
|
void check(const char code[], Settings *settings, const char* filename = "test.cpp") {
|
||||||
// Clear the error buffer..
|
// Clear the error buffer..
|
||||||
errout.str("");
|
errout.str("");
|
||||||
|
|
||||||
settings0.certainty.setEnabled(Certainty::inconclusive, inconclusive);
|
|
||||||
|
|
||||||
// Raw tokens..
|
// Raw tokens..
|
||||||
std::vector<std::string> files(1, filename);
|
std::vector<std::string> files(1, filename);
|
||||||
std::istringstream istr(code);
|
std::istringstream istr(code);
|
||||||
|
@ -141,18 +145,23 @@ private:
|
||||||
std::map<std::string, simplecpp::TokenList*> filedata;
|
std::map<std::string, simplecpp::TokenList*> filedata;
|
||||||
simplecpp::preprocess(tokens2, tokens1, files, filedata, simplecpp::DUI());
|
simplecpp::preprocess(tokens2, tokens1, files, filedata, simplecpp::DUI());
|
||||||
|
|
||||||
Preprocessor preprocessor(settings0, nullptr);
|
Preprocessor preprocessor(*settings, nullptr);
|
||||||
preprocessor.setDirectives(tokens1);
|
preprocessor.setDirectives(tokens1);
|
||||||
|
|
||||||
// Tokenizer..
|
// Tokenizer..
|
||||||
Tokenizer tokenizer(&settings0, this);
|
Tokenizer tokenizer(settings, this);
|
||||||
tokenizer.createTokens(std::move(tokens2));
|
tokenizer.createTokens(std::move(tokens2));
|
||||||
tokenizer.simplifyTokens1("");
|
tokenizer.simplifyTokens1("");
|
||||||
tokenizer.setPreprocessor(&preprocessor);
|
tokenizer.setPreprocessor(&preprocessor);
|
||||||
|
|
||||||
// Run checks..
|
// Run checks..
|
||||||
CheckCondition checkCondition;
|
CheckCondition checkCondition;
|
||||||
checkCondition.runChecks(&tokenizer, &settings0, this);
|
checkCondition.runChecks(&tokenizer, settings, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void check(const char code[], const char* filename = "test.cpp", bool inconclusive = false) {
|
||||||
|
settings0.certainty.setEnabled(Certainty::inconclusive, inconclusive);
|
||||||
|
check(code, &settings0, filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
void assignAndCompare() {
|
void assignAndCompare() {
|
||||||
|
@ -4288,6 +4297,17 @@ private:
|
||||||
"}");
|
"}");
|
||||||
ASSERT_EQUALS("", errout.str());
|
ASSERT_EQUALS("", errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void compareOutOfTypeRange() {
|
||||||
|
Settings settingsUnix64;
|
||||||
|
settingsUnix64.severity.enable(Severity::style);
|
||||||
|
settingsUnix64.platform(cppcheck::Platform::PlatformType::Unix64);
|
||||||
|
|
||||||
|
check("void f(unsigned char c) {\n"
|
||||||
|
" if (c == 1234) {}\n"
|
||||||
|
"}", &settingsUnix64);
|
||||||
|
ASSERT_EQUALS("[test.cpp:2]: (style) Comparing expression of type 'unsigned char' against value 1234. Condition is always true/false.\n", errout.str());
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
REGISTER_TEST(TestCondition)
|
REGISTER_TEST(TestCondition)
|
||||||
|
|
Loading…
Reference in New Issue