Clarify STL out of bounds warning message
This commit is contained in:
parent
682069d512
commit
3c30d274a0
|
@ -70,7 +70,7 @@ void CheckStl::outOfBounds()
|
||||||
if (!value.errorSeverity() && !mSettings->isEnabled(Settings::WARNING))
|
if (!value.errorSeverity() && !mSettings->isEnabled(Settings::WARNING))
|
||||||
continue;
|
continue;
|
||||||
if (value.intvalue == 0 && Token::Match(tok, "%name% . %name% (") && container->getYield(tok->strAt(2)) == Library::Container::Yield::ITEM) {
|
if (value.intvalue == 0 && Token::Match(tok, "%name% . %name% (") && container->getYield(tok->strAt(2)) == Library::Container::Yield::ITEM) {
|
||||||
outOfBoundsError(tok, &value, nullptr);
|
outOfBoundsError(tok->tokAt(3), tok->str(), &value, tok->strAt(2), nullptr);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (Token::Match(tok, "%name% . %name% (") && container->getYield(tok->strAt(2)) == Library::Container::Yield::START_ITERATOR) {
|
if (Token::Match(tok, "%name% . %name% (") && container->getYield(tok->strAt(2)) == Library::Container::Yield::START_ITERATOR) {
|
||||||
|
@ -81,26 +81,26 @@ void CheckStl::outOfBounds()
|
||||||
else if (Token::simpleMatch(parent, "+") && parent->astOperand2() && parent->astOperand2()->hasKnownIntValue())
|
else if (Token::simpleMatch(parent, "+") && parent->astOperand2() && parent->astOperand2()->hasKnownIntValue())
|
||||||
other = parent->astOperand2();
|
other = parent->astOperand2();
|
||||||
if (other && other->getKnownIntValue() > value.intvalue) {
|
if (other && other->getKnownIntValue() > value.intvalue) {
|
||||||
outOfBoundsError(tok, &value, &other->values().back());
|
outOfBoundsError(parent, tok->str(), &value, other->expressionString(), &other->values().back());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!container->arrayLike_indexOp && !container->stdStringLike)
|
if (!container->arrayLike_indexOp && !container->stdStringLike)
|
||||||
continue;
|
continue;
|
||||||
if (value.intvalue == 0 && Token::Match(tok, "%name% [")) {
|
if (value.intvalue == 0 && Token::Match(tok, "%name% [")) {
|
||||||
outOfBoundsError(tok, &value, nullptr);
|
outOfBoundsError(tok->next(), tok->str(), &value, "", nullptr);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (container->arrayLike_indexOp && Token::Match(tok, "%name% [")) {
|
if (container->arrayLike_indexOp && Token::Match(tok, "%name% [")) {
|
||||||
const ValueFlow::Value *indexValue = tok->next()->astOperand2() ? tok->next()->astOperand2()->getMaxValue(false) : nullptr;
|
const ValueFlow::Value *indexValue = tok->next()->astOperand2() ? tok->next()->astOperand2()->getMaxValue(false) : nullptr;
|
||||||
if (indexValue && indexValue->intvalue >= value.intvalue) {
|
if (indexValue && indexValue->intvalue >= value.intvalue) {
|
||||||
outOfBoundsError(tok, &value, indexValue);
|
outOfBoundsError(tok->next(), tok->str(), &value, tok->next()->astOperand2()->expressionString(), indexValue);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (mSettings->isEnabled(Settings::WARNING)) {
|
if (mSettings->isEnabled(Settings::WARNING)) {
|
||||||
indexValue = tok->next()->astOperand2() ? tok->next()->astOperand2()->getMaxValue(true) : nullptr;
|
indexValue = tok->next()->astOperand2() ? tok->next()->astOperand2()->getMaxValue(true) : nullptr;
|
||||||
if (indexValue && indexValue->intvalue >= value.intvalue) {
|
if (indexValue && indexValue->intvalue >= value.intvalue) {
|
||||||
outOfBoundsError(tok, &value, indexValue);
|
outOfBoundsError(tok->next(), tok->str(), &value, tok->next()->astOperand2()->expressionString(), indexValue);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -110,39 +110,40 @@ void CheckStl::outOfBounds()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CheckStl::outOfBoundsError(const Token *tok, const ValueFlow::Value *containerSize, const ValueFlow::Value *index)
|
void CheckStl::outOfBoundsError(const Token *tok, const std::string &containerName, const ValueFlow::Value *containerSize, const std::string &index, const ValueFlow::Value *indexValue)
|
||||||
{
|
{
|
||||||
// Do not warn if both the container size and index are possible
|
// Do not warn if both the container size and index value are possible
|
||||||
if (containerSize && index && containerSize->isPossible() && index->isPossible())
|
if (containerSize && indexValue && containerSize->isPossible() && indexValue->isPossible())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const std::string varname = tok ? tok->str() : std::string("var");
|
const std::string expression = tok ? tok->expressionString() : (containerName+"[x]");
|
||||||
|
|
||||||
std::string errmsg;
|
std::string errmsg;
|
||||||
if (!containerSize)
|
if (!containerSize)
|
||||||
errmsg = "Out of bounds access of item in container '$symbol'";
|
errmsg = "Out of bounds access in expression '" + expression + "'";
|
||||||
else if (containerSize->intvalue == 0) {
|
else if (containerSize->intvalue == 0) {
|
||||||
if (containerSize->condition)
|
if (containerSize->condition)
|
||||||
errmsg = ValueFlow::eitherTheConditionIsRedundant(containerSize->condition) + " or $symbol is accessed out of bounds when $symbol is empty.";
|
errmsg = ValueFlow::eitherTheConditionIsRedundant(containerSize->condition) + " or expression '" + expression + "' cause access out of bounds.";
|
||||||
else
|
else
|
||||||
errmsg = "Out of bounds access in $symbol because $symbol is empty.";
|
errmsg = "Out of bounds access in expression '" + expression + "' because '$symbol' is empty.";
|
||||||
} else if (index) {
|
} else if (indexValue) {
|
||||||
errmsg = "Accessing $symbol[" + MathLib::toString(index->intvalue) + "] is out of bounds when $symbol size is " + MathLib::toString(containerSize->intvalue) + ".";
|
|
||||||
if (containerSize->condition)
|
if (containerSize->condition)
|
||||||
errmsg = ValueFlow::eitherTheConditionIsRedundant(containerSize->condition) + " or $symbol size can be " + MathLib::toString(containerSize->intvalue) + ". " + errmsg;
|
errmsg = ValueFlow::eitherTheConditionIsRedundant(containerSize->condition) + " or $symbol size can be " + MathLib::toString(containerSize->intvalue) + ". Expression '" + expression + "' cause access out of bounds.";
|
||||||
else if (index->condition)
|
else if (indexValue->condition)
|
||||||
errmsg = ValueFlow::eitherTheConditionIsRedundant(index->condition) + " or $symbol item " + MathLib::toString(index->intvalue) + " can be accessed. " + errmsg;
|
errmsg = ValueFlow::eitherTheConditionIsRedundant(indexValue->condition) + " or '" + index + "' can have the value " + MathLib::toString(indexValue->intvalue) + ". Expression '" + expression + "' cause access out of bounds.";
|
||||||
|
else
|
||||||
|
errmsg = "Out of bounds access in '" + expression + "', if '$symbol' size is " + MathLib::toString(containerSize->intvalue) + " and '" + index + "' is " + MathLib::toString(indexValue->intvalue);
|
||||||
} else {
|
} else {
|
||||||
// should not happen
|
// should not happen
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorPath errorPath;
|
ErrorPath errorPath;
|
||||||
if (!index)
|
if (!indexValue)
|
||||||
errorPath = getErrorPath(tok, containerSize, "Access out of bounds");
|
errorPath = getErrorPath(tok, containerSize, "Access out of bounds");
|
||||||
else {
|
else {
|
||||||
ErrorPath errorPath1 = getErrorPath(tok, containerSize, "Access out of bounds");
|
ErrorPath errorPath1 = getErrorPath(tok, containerSize, "Access out of bounds");
|
||||||
ErrorPath errorPath2 = getErrorPath(tok, index, "Access out of bounds");
|
ErrorPath errorPath2 = getErrorPath(tok, indexValue, "Access out of bounds");
|
||||||
if (errorPath1.size() <= 1)
|
if (errorPath1.size() <= 1)
|
||||||
errorPath = errorPath2;
|
errorPath = errorPath2;
|
||||||
else if (errorPath2.size() <= 1)
|
else if (errorPath2.size() <= 1)
|
||||||
|
@ -154,11 +155,11 @@ void CheckStl::outOfBoundsError(const Token *tok, const ValueFlow::Value *contai
|
||||||
}
|
}
|
||||||
|
|
||||||
reportError(errorPath,
|
reportError(errorPath,
|
||||||
(containerSize && !containerSize->errorSeverity()) || (index && !index->errorSeverity()) ? Severity::warning : Severity::error,
|
(containerSize && !containerSize->errorSeverity()) || (indexValue && !indexValue->errorSeverity()) ? Severity::warning : Severity::error,
|
||||||
"containerOutOfBounds",
|
"containerOutOfBounds",
|
||||||
"$symbol:" + varname +"\n" + errmsg,
|
"$symbol:" + containerName +"\n" + errmsg,
|
||||||
CWE398,
|
CWE398,
|
||||||
(containerSize && containerSize->isInconclusive()) || (index && index->isInconclusive()));
|
(containerSize && containerSize->isInconclusive()) || (indexValue && indexValue->isInconclusive()));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CheckStl::isContainerSize(const Token *containerToken, const Token *expr) const
|
bool CheckStl::isContainerSize(const Token *containerToken, const Token *expr) const
|
||||||
|
|
|
@ -185,7 +185,7 @@ private:
|
||||||
void string_c_strReturn(const Token* tok);
|
void string_c_strReturn(const Token* tok);
|
||||||
void string_c_strParam(const Token* tok, unsigned int number);
|
void string_c_strParam(const Token* tok, unsigned int number);
|
||||||
|
|
||||||
void outOfBoundsError(const Token *tok, const ValueFlow::Value *containerSize, const ValueFlow::Value *index);
|
void outOfBoundsError(const Token *tok, const std::string &containerName, const ValueFlow::Value *containerSize, const std::string &index, const ValueFlow::Value *indexValue);
|
||||||
void outOfBoundsIndexExpressionError(const Token *tok, const Token *index);
|
void outOfBoundsIndexExpressionError(const Token *tok, const Token *index);
|
||||||
void stlOutOfBoundsError(const Token* tok, const std::string& num, const std::string& var, bool at);
|
void stlOutOfBoundsError(const Token* tok, const std::string& num, const std::string& var, bool at);
|
||||||
void negativeIndexError(const Token* tok, const ValueFlow::Value& index);
|
void negativeIndexError(const Token* tok, const ValueFlow::Value& index);
|
||||||
|
@ -221,7 +221,7 @@ private:
|
||||||
|
|
||||||
void getErrorMessages(ErrorLogger* errorLogger, const Settings* settings) const OVERRIDE {
|
void getErrorMessages(ErrorLogger* errorLogger, const Settings* settings) const OVERRIDE {
|
||||||
CheckStl c(nullptr, settings, errorLogger);
|
CheckStl c(nullptr, settings, errorLogger);
|
||||||
c.outOfBoundsError(nullptr, nullptr, nullptr);
|
c.outOfBoundsError(nullptr, "container", nullptr, "x", nullptr);
|
||||||
c.invalidIteratorError(nullptr, "iterator");
|
c.invalidIteratorError(nullptr, "iterator");
|
||||||
c.iteratorsError(nullptr, "container1", "container2");
|
c.iteratorsError(nullptr, "container1", "container2");
|
||||||
c.iteratorsError(nullptr, nullptr, "container0", "container1");
|
c.iteratorsError(nullptr, nullptr, "container0", "container1");
|
||||||
|
|
|
@ -201,19 +201,19 @@ private:
|
||||||
" std::string s;\n"
|
" std::string s;\n"
|
||||||
" s[10] = 1;\n"
|
" s[10] = 1;\n"
|
||||||
"}");
|
"}");
|
||||||
ASSERT_EQUALS("test.cpp:3:error:Out of bounds access in s because s is empty.\n", errout.str());
|
ASSERT_EQUALS("test.cpp:3:error:Out of bounds access in expression 's[10]' because 's' is empty.\n", errout.str());
|
||||||
|
|
||||||
checkNormal("void f() {\n"
|
checkNormal("void f() {\n"
|
||||||
" std::string s = \"abcd\";\n"
|
" std::string s = \"abcd\";\n"
|
||||||
" s[10] = 1;\n"
|
" s[10] = 1;\n"
|
||||||
"}");
|
"}");
|
||||||
ASSERT_EQUALS("test.cpp:3:error:Accessing s[10] is out of bounds when s size is 4.\n", errout.str());
|
ASSERT_EQUALS("test.cpp:3:error:Out of bounds access in 's[10]', if 's' size is 4 and '10' is 10\n", errout.str());
|
||||||
|
|
||||||
checkNormal("void f(std::vector<int> v) {\n"
|
checkNormal("void f(std::vector<int> v) {\n"
|
||||||
" v.front();\n"
|
" v.front();\n"
|
||||||
" if (v.empty()) {}\n"
|
" if (v.empty()) {}\n"
|
||||||
"}\n");
|
"}\n");
|
||||||
ASSERT_EQUALS("test.cpp:2:warning:Either the condition 'v.empty()' is redundant or v is accessed out of bounds when v is empty.\n"
|
ASSERT_EQUALS("test.cpp:2:warning:Either the condition 'v.empty()' is redundant or expression 'v.front()' cause access out of bounds.\n"
|
||||||
"test.cpp:3:note:condition 'v.empty()'\n"
|
"test.cpp:3:note:condition 'v.empty()'\n"
|
||||||
"test.cpp:2:note:Access out of bounds\n", errout.str());
|
"test.cpp:2:note:Access out of bounds\n", errout.str());
|
||||||
|
|
||||||
|
@ -221,7 +221,7 @@ private:
|
||||||
" if (v.size() == 3) {}\n"
|
" if (v.size() == 3) {}\n"
|
||||||
" v[16] = 0;\n"
|
" v[16] = 0;\n"
|
||||||
"}\n");
|
"}\n");
|
||||||
ASSERT_EQUALS("test.cpp:3:warning:Either the condition 'v.size()==3' is redundant or v size can be 3. Accessing v[16] is out of bounds when v size is 3.\n"
|
ASSERT_EQUALS("test.cpp:3:warning:Either the condition 'v.size()==3' is redundant or v size can be 3. Expression 'v[16]' cause access out of bounds.\n"
|
||||||
"test.cpp:2:note:condition 'v.size()==3'\n"
|
"test.cpp:2:note:condition 'v.size()==3'\n"
|
||||||
"test.cpp:3:note:Access out of bounds\n", errout.str());
|
"test.cpp:3:note:Access out of bounds\n", errout.str());
|
||||||
|
|
||||||
|
@ -231,7 +231,7 @@ private:
|
||||||
" v[i] = 0;\n"
|
" v[i] = 0;\n"
|
||||||
" }\n"
|
" }\n"
|
||||||
"}\n");
|
"}\n");
|
||||||
ASSERT_EQUALS("test.cpp:4:warning:Either the condition 'v.size()==3' is redundant or v size can be 3. Accessing v[16] is out of bounds when v size is 3.\n"
|
ASSERT_EQUALS("test.cpp:4:warning:Either the condition 'v.size()==3' is redundant or v size can be 3. Expression 'v[i]' cause access out of bounds.\n"
|
||||||
"test.cpp:3:note:condition 'v.size()==3'\n"
|
"test.cpp:3:note:condition 'v.size()==3'\n"
|
||||||
"test.cpp:4:note:Access out of bounds\n", errout.str());
|
"test.cpp:4:note:Access out of bounds\n", errout.str());
|
||||||
|
|
||||||
|
@ -251,7 +251,7 @@ private:
|
||||||
" s[2] = 0;\n"
|
" s[2] = 0;\n"
|
||||||
" }\n"
|
" }\n"
|
||||||
"}\n");
|
"}\n");
|
||||||
ASSERT_EQUALS("test.cpp:3:warning:Either the condition 's.size()==1' is redundant or s size can be 1. Accessing s[2] is out of bounds when s size is 1.\n"
|
ASSERT_EQUALS("test.cpp:3:warning:Either the condition 's.size()==1' is redundant or s size can be 1. Expression 's[2]' cause access out of bounds.\n"
|
||||||
"test.cpp:2:note:condition 's.size()==1'\n"
|
"test.cpp:2:note:condition 's.size()==1'\n"
|
||||||
"test.cpp:3:note:Access out of bounds\n", errout.str());
|
"test.cpp:3:note:Access out of bounds\n", errout.str());
|
||||||
|
|
||||||
|
@ -279,7 +279,7 @@ private:
|
||||||
" std::string s;\n"
|
" std::string s;\n"
|
||||||
" x = s.begin() + 1;\n"
|
" x = s.begin() + 1;\n"
|
||||||
"}\n");
|
"}\n");
|
||||||
ASSERT_EQUALS("test.cpp:3:error:Out of bounds access in s because s is empty.\n", errout.str());
|
ASSERT_EQUALS("test.cpp:3:error:Out of bounds access in expression 's.begin()+1' because 's' is empty.\n", errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void outOfBoundsIndexExpression() {
|
void outOfBoundsIndexExpression() {
|
||||||
|
|
Loading…
Reference in New Issue