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