Fix 10728: Crash in CheckStl::checkDereferenceInvalidIterator2 (#3721)

* Fix 10728: Crash in CheckStl::checkDereferenceInvalidIterator2

* Format
This commit is contained in:
Paul Fultz II 2022-01-18 07:48:02 -06:00 committed by GitHub
parent b6c010c17e
commit 7b793af451
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 29 additions and 10 deletions

View File

@ -994,7 +994,7 @@ void CheckBufferOverrun::objectIndex()
if (idx->hasKnownIntValue() && idx->getKnownIntValue() == 0)
continue;
std::vector<ValueFlow::Value> values = getLifetimeObjValues(obj, false, true);
std::vector<ValueFlow::Value> values = getLifetimeObjValues(obj, false, -1);
for (const ValueFlow::Value& v:values) {
if (v.lifetimeKind != ValueFlow::Value::LifetimeKind::Address)
continue;

View File

@ -728,9 +728,9 @@ static bool isSameIteratorContainerExpression(const Token* tok1,
return false;
}
static ValueFlow::Value getLifetimeIteratorValue(const Token* tok)
static ValueFlow::Value getLifetimeIteratorValue(const Token* tok, MathLib::bigint path = 0)
{
std::vector<ValueFlow::Value> values = getLifetimeObjValues(tok);
std::vector<ValueFlow::Value> values = getLifetimeObjValues(tok, false, path);
auto it = std::find_if(values.begin(), values.end(), [](const ValueFlow::Value& v) {
return v.lifetimeKind == ValueFlow::Value::LifetimeKind::Iterator;
});
@ -2294,6 +2294,8 @@ void CheckStl::checkDereferenceInvalidIterator2()
isInvalidIterator = true;
} else {
auto it = std::find_if(contValues.begin(), contValues.end(), [&](const ValueFlow::Value& c) {
if (value.path != c.path)
return false;
if (value.isIteratorStartValue() && value.intvalue >= c.intvalue)
return true;
if (value.isIteratorEndValue() && -value.intvalue > c.intvalue)
@ -2329,7 +2331,7 @@ void CheckStl::checkDereferenceInvalidIterator2()
inconclusive = true;
}
if (cValue) {
const ValueFlow::Value& lValue = getLifetimeIteratorValue(tok);
const ValueFlow::Value& lValue = getLifetimeIteratorValue(tok, cValue->path);
if (emptyAdvance)
outOfBoundsError(emptyAdvance,
lValue.tokvalue->expressionString(),

View File

@ -2426,7 +2426,7 @@ const ValueFlow::Value* Token::getMaxValue(bool condition, MathLib::bigint path)
continue;
if (value.isImpossible())
continue;
if (value.path != 0 && value.path != path)
if (path > -0 && value.path != 0 && value.path != path)
continue;
if ((!ret || value.intvalue > ret->intvalue) &&
((value.condition != nullptr) == condition))

View File

@ -2973,16 +2973,18 @@ std::string lifetimeMessage(const Token *tok, const ValueFlow::Value *val, Error
return msg;
}
std::vector<ValueFlow::Value> getLifetimeObjValues(const Token *tok, bool inconclusive, bool subfunction)
std::vector<ValueFlow::Value> getLifetimeObjValues(const Token* tok, bool inconclusive, MathLib::bigint path)
{
std::vector<ValueFlow::Value> result;
auto pred = [&](const ValueFlow::Value &v) {
if (!v.isLocalLifetimeValue() && !(subfunction && v.isSubFunctionLifetimeValue()))
auto pred = [&](const ValueFlow::Value& v) {
if (!v.isLocalLifetimeValue() && !(path != 0 && v.isSubFunctionLifetimeValue()))
return false;
if (!inconclusive && v.isInconclusive())
return false;
if (!v.tokvalue)
return false;
if (path >= 0 && v.path != 0 && v.path != path)
return false;
return true;
};
std::copy_if(tok->values().begin(), tok->values().end(), std::back_inserter(result), pred);
@ -2991,7 +2993,7 @@ std::vector<ValueFlow::Value> getLifetimeObjValues(const Token *tok, bool inconc
ValueFlow::Value getLifetimeObjValue(const Token *tok, bool inconclusive)
{
std::vector<ValueFlow::Value> values = getLifetimeObjValues(tok, inconclusive, false);
std::vector<ValueFlow::Value> values = getLifetimeObjValues(tok, inconclusive);
// There should only be one lifetime
if (values.size() != 1)
return ValueFlow::Value{};

View File

@ -513,6 +513,8 @@ std::string lifetimeMessage(const Token *tok, const ValueFlow::Value *val, Value
CPPCHECKLIB ValueFlow::Value getLifetimeObjValue(const Token *tok, bool inconclusive = false);
CPPCHECKLIB std::vector<ValueFlow::Value> getLifetimeObjValues(const Token *tok, bool inconclusive = false, bool subfunction = false);
CPPCHECKLIB std::vector<ValueFlow::Value> getLifetimeObjValues(const Token* tok,
bool inconclusive = false,
MathLib::bigint path = 0);
#endif // valueflowH

View File

@ -692,6 +692,19 @@ private:
"test.cpp:2:note:condition 'i<=(int)v.size()'\n"
"test.cpp:3:note:Access out of bounds\n",
errout.str());
check("template<class Iterator>\n"
"void b(Iterator d) {\n"
" std::string c = \"a\";\n"
" d + c.length();\n"
"}\n"
"void f() {\n"
" std::string buf;\n"
" b(buf.begin());\n"
"}\n",
true);
ASSERT_EQUALS("test.cpp:4:error:Out of bounds access in expression 'd+c.length()' because 'buf' is empty.\n",
errout.str());
}
void outOfBoundsSymbolic()