Fix 10728: Crash in CheckStl::checkDereferenceInvalidIterator2 (#3721)
* Fix 10728: Crash in CheckStl::checkDereferenceInvalidIterator2 * Format
This commit is contained in:
parent
b6c010c17e
commit
7b793af451
|
@ -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;
|
||||||
|
|
|
@ -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(),
|
||||||
|
|
|
@ -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))
|
||||||
|
|
|
@ -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{};
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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()
|
||||||
|
|
Loading…
Reference in New Issue