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) if (idx->hasKnownIntValue() && idx->getKnownIntValue() == 0)
continue; 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) { for (const ValueFlow::Value& v:values) {
if (v.lifetimeKind != ValueFlow::Value::LifetimeKind::Address) if (v.lifetimeKind != ValueFlow::Value::LifetimeKind::Address)
continue; continue;

View File

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

View File

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

View File

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

View File

@ -692,6 +692,19 @@ private:
"test.cpp:2:note:condition 'i<=(int)v.size()'\n" "test.cpp:2:note:condition 'i<=(int)v.size()'\n"
"test.cpp:3:note:Access out of bounds\n", "test.cpp:3:note:Access out of bounds\n",
errout.str()); 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() void outOfBoundsSymbolic()