parent
5f21d9d97b
commit
1858465bca
|
@ -920,18 +920,18 @@ void CheckBufferOverrun::objectIndex()
|
|||
std::copy_if(idx->values().begin(),
|
||||
idx->values().end(),
|
||||
std::back_inserter(idxValues),
|
||||
[&](const ValueFlow::Value& vidx) {
|
||||
if (!vidx.isIntValue())
|
||||
return false;
|
||||
return vidx.path == v.path || vidx.path == 0;
|
||||
});
|
||||
[&](const ValueFlow::Value& vidx) {
|
||||
if (!vidx.isIntValue())
|
||||
return false;
|
||||
return vidx.path == v.path || vidx.path == 0;
|
||||
});
|
||||
if (idxValues.empty() ||
|
||||
std::any_of(idxValues.begin(), idxValues.end(), [&](const ValueFlow::Value& vidx) {
|
||||
if (vidx.isImpossible())
|
||||
return (vidx.intvalue == 0);
|
||||
else
|
||||
return (vidx.intvalue != 0);
|
||||
})) {
|
||||
std::any_of(idxValues.begin(), idxValues.end(), [&](const ValueFlow::Value& vidx) {
|
||||
if (vidx.isImpossible())
|
||||
return (vidx.intvalue == 0);
|
||||
else
|
||||
return (vidx.intvalue != 0);
|
||||
})) {
|
||||
objectIndexError(tok, &v, idx->hasKnownIntValue());
|
||||
}
|
||||
} else {
|
||||
|
|
105
lib/checkstl.cpp
105
lib/checkstl.cpp
|
@ -854,21 +854,18 @@ struct InvalidContainerAnalyzer {
|
|||
};
|
||||
std::unordered_map<int, Reference> expressions;
|
||||
ErrorPath errorPath;
|
||||
void add(const std::vector<Reference>& refs)
|
||||
{
|
||||
void add(const std::vector<Reference>& refs) {
|
||||
for (const Reference& r : refs) {
|
||||
add(r);
|
||||
}
|
||||
}
|
||||
void add(const Reference& r)
|
||||
{
|
||||
void add(const Reference& r) {
|
||||
if (!r.tok)
|
||||
return;
|
||||
expressions.insert(std::make_pair(r.tok->exprId(), r));
|
||||
}
|
||||
|
||||
std::vector<Reference> invalidTokens() const
|
||||
{
|
||||
std::vector<Reference> invalidTokens() const {
|
||||
std::vector<Reference> result;
|
||||
std::transform(expressions.begin(), expressions.end(), std::back_inserter(result), SelectMapValues{});
|
||||
return result;
|
||||
|
@ -876,8 +873,7 @@ struct InvalidContainerAnalyzer {
|
|||
};
|
||||
std::unordered_map<const Function*, Info> invalidMethods;
|
||||
|
||||
std::vector<Info::Reference> invalidatesContainer(const Token* tok) const
|
||||
{
|
||||
std::vector<Info::Reference> invalidatesContainer(const Token* tok) const {
|
||||
std::vector<Info::Reference> result;
|
||||
if (Token::Match(tok, "%name% (")) {
|
||||
const Function* f = tok->function();
|
||||
|
@ -920,15 +916,14 @@ struct InvalidContainerAnalyzer {
|
|||
ErrorPath ep;
|
||||
ep.emplace_front(tok,
|
||||
"After calling '" + tok->strAt(2) +
|
||||
"', iterators or references to the container's data may be invalid .");
|
||||
"', iterators or references to the container's data may be invalid .");
|
||||
result.push_back(Info::Reference{tok, ep});
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void analyze(const SymbolDatabase* symboldatabase)
|
||||
{
|
||||
void analyze(const SymbolDatabase* symboldatabase) {
|
||||
for (const Scope* scope : symboldatabase->functionScopes) {
|
||||
const Function* f = scope->function;
|
||||
if (!f)
|
||||
|
@ -990,55 +985,55 @@ void CheckStl::invalidContainer()
|
|||
const ValueFlow::Value* v = nullptr;
|
||||
ErrorPath errorPath;
|
||||
PathAnalysis::Info info =
|
||||
PathAnalysis{endToken, library}.forwardFind([&](const PathAnalysis::Info& info) {
|
||||
if (!info.tok->variable())
|
||||
return false;
|
||||
if (info.tok->varId() == 0)
|
||||
return false;
|
||||
if (skipVarIds.count(info.tok->varId()) > 0)
|
||||
return false;
|
||||
// if (Token::simpleMatch(info.tok->next(), "."))
|
||||
// return false;
|
||||
if (Token::Match(info.tok->astParent(), "%assign%") && astIsLHS(info.tok))
|
||||
skipVarIds.insert(info.tok->varId());
|
||||
if (info.tok->variable()->isReference() && !isVariableDecl(info.tok) &&
|
||||
reaches(info.tok->variable()->nameToken(), tok, library, nullptr)) {
|
||||
PathAnalysis{endToken, library} .forwardFind([&](const PathAnalysis::Info& info) {
|
||||
if (!info.tok->variable())
|
||||
return false;
|
||||
if (info.tok->varId() == 0)
|
||||
return false;
|
||||
if (skipVarIds.count(info.tok->varId()) > 0)
|
||||
return false;
|
||||
// if (Token::simpleMatch(info.tok->next(), "."))
|
||||
// return false;
|
||||
if (Token::Match(info.tok->astParent(), "%assign%") && astIsLHS(info.tok))
|
||||
skipVarIds.insert(info.tok->varId());
|
||||
if (info.tok->variable()->isReference() && !isVariableDecl(info.tok) &&
|
||||
reaches(info.tok->variable()->nameToken(), tok, library, nullptr)) {
|
||||
|
||||
ErrorPath ep;
|
||||
bool addressOf = false;
|
||||
const Variable* var = getLifetimeVariable(info.tok, ep, &addressOf);
|
||||
// Check the reference is created before the change
|
||||
if (var && var->declarationId() == r.tok->varId() && !addressOf) {
|
||||
// An argument always reaches
|
||||
if (var->isArgument() ||
|
||||
(!var->isReference() && !var->isRValueReference() && !isVariableDecl(tok) &&
|
||||
reaches(var->nameToken(), tok, library, &ep))) {
|
||||
errorPath = ep;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const ValueFlow::Value& val : info.tok->values()) {
|
||||
if (!val.isLocalLifetimeValue())
|
||||
continue;
|
||||
if (val.lifetimeKind == ValueFlow::Value::LifetimeKind::Address)
|
||||
continue;
|
||||
if (val.lifetimeKind == ValueFlow::Value::LifetimeKind::SubObject)
|
||||
continue;
|
||||
if (!val.tokvalue->variable())
|
||||
continue;
|
||||
if (val.tokvalue->varId() != r.tok->varId())
|
||||
continue;
|
||||
ErrorPath ep;
|
||||
// Check the iterator is created before the change
|
||||
if (val.tokvalue != tok && reaches(val.tokvalue, tok, library, &ep)) {
|
||||
v = &val;
|
||||
ErrorPath ep;
|
||||
bool addressOf = false;
|
||||
const Variable* var = getLifetimeVariable(info.tok, ep, &addressOf);
|
||||
// Check the reference is created before the change
|
||||
if (var && var->declarationId() == r.tok->varId() && !addressOf) {
|
||||
// An argument always reaches
|
||||
if (var->isArgument() ||
|
||||
(!var->isReference() && !var->isRValueReference() && !isVariableDecl(tok) &&
|
||||
reaches(var->nameToken(), tok, library, &ep))) {
|
||||
errorPath = ep;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
for (const ValueFlow::Value& val : info.tok->values()) {
|
||||
if (!val.isLocalLifetimeValue())
|
||||
continue;
|
||||
if (val.lifetimeKind == ValueFlow::Value::LifetimeKind::Address)
|
||||
continue;
|
||||
if (val.lifetimeKind == ValueFlow::Value::LifetimeKind::SubObject)
|
||||
continue;
|
||||
if (!val.tokvalue->variable())
|
||||
continue;
|
||||
if (val.tokvalue->varId() != r.tok->varId())
|
||||
continue;
|
||||
ErrorPath ep;
|
||||
// Check the iterator is created before the change
|
||||
if (val.tokvalue != tok && reaches(val.tokvalue, tok, library, &ep)) {
|
||||
v = &val;
|
||||
errorPath = ep;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
});
|
||||
if (!info.tok)
|
||||
continue;
|
||||
errorPath.insert(errorPath.end(), info.errorPath.begin(), info.errorPath.end());
|
||||
|
|
|
@ -30,16 +30,14 @@
|
|||
|
||||
struct SelectMapKeys {
|
||||
template <class Pair>
|
||||
typename Pair::first_type operator()(const Pair& p) const
|
||||
{
|
||||
typename Pair::first_type operator()(const Pair& p) const {
|
||||
return p.first;
|
||||
}
|
||||
};
|
||||
|
||||
struct SelectMapValues {
|
||||
template <class Pair>
|
||||
typename Pair::second_type operator()(const Pair& p) const
|
||||
{
|
||||
typename Pair::second_type operator()(const Pair& p) const {
|
||||
return p.second;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -353,18 +353,21 @@ static bool isComputableValue(const Token* parent, const ValueFlow::Value& value
|
|||
}
|
||||
|
||||
template<class T>
|
||||
static bool isEqual(T x, T y) {
|
||||
static bool isEqual(T x, T y)
|
||||
{
|
||||
return x == y;
|
||||
}
|
||||
|
||||
template<>
|
||||
bool isEqual<double>(double x, double y) {
|
||||
bool isEqual<double>(double x, double y)
|
||||
{
|
||||
const double diff = (x > y) ? x - y : y - x;
|
||||
return !((diff / 2) < diff);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
static bool isZero(T x) {
|
||||
static bool isZero(T x)
|
||||
{
|
||||
return isEqual<T>(x, T(0));
|
||||
}
|
||||
|
||||
|
@ -2306,8 +2309,8 @@ struct OppositeExpressionAnalyzer : ExpressionAnalyzer {
|
|||
OppositeExpressionAnalyzer() : ExpressionAnalyzer(), isNot(false) {}
|
||||
|
||||
OppositeExpressionAnalyzer(bool pIsNot, const Token* e, const ValueFlow::Value& val, const TokenList* t)
|
||||
: ExpressionAnalyzer(e, val, t), isNot(pIsNot)
|
||||
{}
|
||||
: ExpressionAnalyzer(e, val, t), isNot(pIsNot)
|
||||
{}
|
||||
|
||||
virtual bool match(const Token* tok) const OVERRIDE {
|
||||
return isOppositeCond(isNot, isCPP(), expr, tok, getSettings()->library, true, true);
|
||||
|
@ -4973,7 +4976,7 @@ struct MultiValueFlowAnalyzer : ValueFlowAnalyzer {
|
|||
if (scope && condTok)
|
||||
programMemoryParseCondition(pm, condTok, nullptr, getSettings(), scope->type != Scope::eElse);
|
||||
// ProgramMemory pm = pms.get(endBlock->link()->next(), getProgramState());
|
||||
for(const auto& p:pm.values) {
|
||||
for (const auto& p:pm.values) {
|
||||
int varid = p.first;
|
||||
ValueFlow::Value value = p.second;
|
||||
if (vars.count(varid) != 0)
|
||||
|
|
Loading…
Reference in New Issue