Add debug_valueflow instrinsic to show valueflow values and its error path (#4159)
* Add debug_valueflow instrinsic to show valueflow values and its error path * Format
This commit is contained in:
parent
703396e549
commit
e430a11b49
|
@ -1782,56 +1782,7 @@ void Token::printValueFlow(bool xml, std::ostream &out) const
|
|||
else {
|
||||
if (&value != &tok->mImpl->mValues->front())
|
||||
out << ",";
|
||||
if (value.isImpossible())
|
||||
out << "!";
|
||||
if (value.bound == ValueFlow::Value::Bound::Lower)
|
||||
out << ">=";
|
||||
if (value.bound == ValueFlow::Value::Bound::Upper)
|
||||
out << "<=";
|
||||
switch (value.valueType) {
|
||||
case ValueFlow::Value::ValueType::INT:
|
||||
out << value.intvalue;
|
||||
break;
|
||||
case ValueFlow::Value::ValueType::TOK:
|
||||
out << value.tokvalue->str();
|
||||
break;
|
||||
case ValueFlow::Value::ValueType::FLOAT:
|
||||
out << value.floatValue;
|
||||
break;
|
||||
case ValueFlow::Value::ValueType::MOVED:
|
||||
out << ValueFlow::Value::toString(value.moveKind);
|
||||
break;
|
||||
case ValueFlow::Value::ValueType::UNINIT:
|
||||
out << "Uninit";
|
||||
break;
|
||||
case ValueFlow::Value::ValueType::BUFFER_SIZE:
|
||||
case ValueFlow::Value::ValueType::CONTAINER_SIZE:
|
||||
out << "size=" << value.intvalue;
|
||||
break;
|
||||
case ValueFlow::Value::ValueType::ITERATOR_START:
|
||||
out << "start=" << value.intvalue;
|
||||
break;
|
||||
case ValueFlow::Value::ValueType::ITERATOR_END:
|
||||
out << "end=" << value.intvalue;
|
||||
break;
|
||||
case ValueFlow::Value::ValueType::LIFETIME:
|
||||
out << "lifetime[" << ValueFlow::Value::toString(value.lifetimeKind) << "]=("
|
||||
<< value.tokvalue->expressionString() << ")";
|
||||
break;
|
||||
case ValueFlow::Value::ValueType::SYMBOLIC:
|
||||
out << "symbolic=(" << value.tokvalue->expressionString();
|
||||
if (value.intvalue > 0)
|
||||
out << "+" << value.intvalue;
|
||||
else if (value.intvalue < 0)
|
||||
out << "-" << -value.intvalue;
|
||||
out << ")";
|
||||
break;
|
||||
}
|
||||
if (value.indirect > 0)
|
||||
for (int i=0; i<value.indirect; i++)
|
||||
out << "*";
|
||||
if (value.path > 0)
|
||||
out << "@" << value.path;
|
||||
out << value.toString();
|
||||
}
|
||||
}
|
||||
if (xml)
|
||||
|
|
53
lib/token.h
53
lib/token.h
|
@ -65,6 +65,8 @@ struct ScopeInfo2 {
|
|||
std::set<std::string> usingNamespaces;
|
||||
};
|
||||
|
||||
enum class TokenDebug { None, ValueFlow };
|
||||
|
||||
struct TokenImpl {
|
||||
nonneg int mVarId;
|
||||
nonneg int mFileIndex;
|
||||
|
@ -127,30 +129,34 @@ struct TokenImpl {
|
|||
/** Bitfield bit count. */
|
||||
unsigned char mBits;
|
||||
|
||||
TokenDebug mDebug;
|
||||
|
||||
void setCppcheckAttribute(CppcheckAttributes::Type type, MathLib::bigint value);
|
||||
bool getCppcheckAttribute(CppcheckAttributes::Type type, MathLib::bigint *value) const;
|
||||
|
||||
TokenImpl()
|
||||
: mVarId(0)
|
||||
, mFileIndex(0)
|
||||
, mLineNumber(0)
|
||||
, mColumn(0)
|
||||
, mExprId(0)
|
||||
, mAstOperand1(nullptr)
|
||||
, mAstOperand2(nullptr)
|
||||
, mAstParent(nullptr)
|
||||
, mScope(nullptr)
|
||||
, mFunction(nullptr) // Initialize whole union
|
||||
, mProgressValue(0)
|
||||
, mIndex(0)
|
||||
, mOriginalName(nullptr)
|
||||
, mValueType(nullptr)
|
||||
, mValues(nullptr)
|
||||
, mTemplateSimplifierPointers(nullptr)
|
||||
, mScopeInfo(nullptr)
|
||||
, mCppcheckAttributes(nullptr)
|
||||
, mCpp11init(Cpp11init::UNKNOWN)
|
||||
, mBits(0)
|
||||
: mVarId(0),
|
||||
mFileIndex(0),
|
||||
mLineNumber(0),
|
||||
mColumn(0),
|
||||
mExprId(0),
|
||||
mAstOperand1(nullptr),
|
||||
mAstOperand2(nullptr),
|
||||
mAstParent(nullptr),
|
||||
mScope(nullptr),
|
||||
mFunction(nullptr) // Initialize whole union
|
||||
,
|
||||
mProgressValue(0),
|
||||
mIndex(0),
|
||||
mOriginalName(nullptr),
|
||||
mValueType(nullptr),
|
||||
mValues(nullptr),
|
||||
mTemplateSimplifierPointers(nullptr),
|
||||
mScopeInfo(nullptr),
|
||||
mCppcheckAttributes(nullptr),
|
||||
mCpp11init(Cpp11init::UNKNOWN),
|
||||
mBits(0),
|
||||
mDebug(TokenDebug::None)
|
||||
{}
|
||||
|
||||
~TokenImpl();
|
||||
|
@ -1437,6 +1443,13 @@ public:
|
|||
TokenImpl::Cpp11init isCpp11init() const {
|
||||
return mImpl->mCpp11init;
|
||||
}
|
||||
|
||||
TokenDebug getTokenDebug() const {
|
||||
return mImpl->mDebug;
|
||||
}
|
||||
void setTokenDebug(TokenDebug td) {
|
||||
mImpl->mDebug = td;
|
||||
}
|
||||
};
|
||||
|
||||
Token* findTypeEnd(Token* tok);
|
||||
|
|
|
@ -4855,6 +4855,9 @@ bool Tokenizer::simplifyTokenList1(const char FileName[])
|
|||
|
||||
createLinks();
|
||||
|
||||
// Simplify debug intrinsics
|
||||
simplifyDebug();
|
||||
|
||||
removePragma();
|
||||
|
||||
// Simplify the C alternative tokens (and, or, etc.)
|
||||
|
@ -11333,6 +11336,33 @@ void Tokenizer::simplifyKeyword()
|
|||
}
|
||||
}
|
||||
|
||||
static Token* setTokenDebug(Token* start, TokenDebug td)
|
||||
{
|
||||
if (!start->link())
|
||||
return nullptr;
|
||||
Token* end = start->link();
|
||||
start->deleteThis();
|
||||
for (Token* tok = start; tok != end; tok = tok->next()) {
|
||||
tok->setTokenDebug(td);
|
||||
}
|
||||
end->deleteThis();
|
||||
return end;
|
||||
}
|
||||
|
||||
void Tokenizer::simplifyDebug()
|
||||
{
|
||||
if (!mSettings->debugnormal && !mSettings->debugwarnings)
|
||||
return;
|
||||
for (Token* tok = list.front(); tok; tok = tok->next()) {
|
||||
if (!Token::Match(tok, "%name% ("))
|
||||
continue;
|
||||
if (Token::simpleMatch(tok, "debug_valueflow")) {
|
||||
tok->deleteThis();
|
||||
tok = setTokenDebug(tok, TokenDebug::ValueFlow);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Tokenizer::simplifyAssignmentInFunctionCall()
|
||||
{
|
||||
for (Token *tok = list.front(); tok; tok = tok->next()) {
|
||||
|
|
|
@ -209,6 +209,7 @@ public:
|
|||
*/
|
||||
nonneg int sizeOfType(const Token *type) const;
|
||||
|
||||
void simplifyDebug();
|
||||
/**
|
||||
* Try to determine if function parameter is passed by value by looking
|
||||
* at the function declaration.
|
||||
|
|
|
@ -344,6 +344,7 @@ Token *TokenList::copyTokens(Token *dest, const Token *first, const Token *last,
|
|||
tok2->tokType(tok->tokType());
|
||||
tok2->flags(tok->flags());
|
||||
tok2->varId(tok->varId());
|
||||
tok2->setTokenDebug(tok->getTokenDebug());
|
||||
|
||||
// Check for links and fix them up
|
||||
if (Token::Match(tok2, "(|[|{"))
|
||||
|
|
|
@ -8299,6 +8299,36 @@ static void valueFlowUnknownFunctionReturn(TokenList *tokenlist, const Settings
|
|||
}
|
||||
}
|
||||
|
||||
static void valueFlowDebug(TokenList* tokenlist, ErrorLogger* errorLogger)
|
||||
{
|
||||
if (!tokenlist->getSettings()->debugnormal && !tokenlist->getSettings()->debugwarnings)
|
||||
return;
|
||||
for (Token* tok = tokenlist->front(); tok; tok = tok->next()) {
|
||||
if (tok->getTokenDebug() != TokenDebug::ValueFlow)
|
||||
continue;
|
||||
for (const ValueFlow::Value& v : tok->values()) {
|
||||
std::string kind;
|
||||
switch (v.valueKind) {
|
||||
|
||||
case ValueFlow::Value::ValueKind::Impossible:
|
||||
case ValueFlow::Value::ValueKind::Known:
|
||||
kind = "always";
|
||||
break;
|
||||
case ValueFlow::Value::ValueKind::Inconclusive:
|
||||
kind = "inconclusive";
|
||||
break;
|
||||
case ValueFlow::Value::ValueKind::Possible:
|
||||
kind = "possible";
|
||||
break;
|
||||
}
|
||||
std::string msg = "The value is " + kind + " " + v.toString();
|
||||
ErrorPath errorPath = v.errorPath;
|
||||
errorPath.emplace_back(tok, "");
|
||||
errorLogger->reportErr({errorPath, tokenlist, Severity::debug, "valueFlow", msg, CWE{0}, Certainty::normal});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ValueFlow::Value::Value(const Token* c, long long val, Bound b)
|
||||
: valueType(ValueType::INT),
|
||||
bound(b),
|
||||
|
@ -8331,6 +8361,62 @@ void ValueFlow::Value::assumeCondition(const Token* tok)
|
|||
errorPath.emplace_back(tok, "Assuming that condition '" + tok->expressionString() + "' is not redundant");
|
||||
}
|
||||
|
||||
std::string ValueFlow::Value::toString() const
|
||||
{
|
||||
std::stringstream ss;
|
||||
if (this->isImpossible())
|
||||
ss << "!";
|
||||
if (this->bound == ValueFlow::Value::Bound::Lower)
|
||||
ss << ">=";
|
||||
if (this->bound == ValueFlow::Value::Bound::Upper)
|
||||
ss << "<=";
|
||||
switch (this->valueType) {
|
||||
case ValueFlow::Value::ValueType::INT:
|
||||
ss << this->intvalue;
|
||||
break;
|
||||
case ValueFlow::Value::ValueType::TOK:
|
||||
ss << this->tokvalue->str();
|
||||
break;
|
||||
case ValueFlow::Value::ValueType::FLOAT:
|
||||
ss << this->floatValue;
|
||||
break;
|
||||
case ValueFlow::Value::ValueType::MOVED:
|
||||
ss << ValueFlow::Value::toString(this->moveKind);
|
||||
break;
|
||||
case ValueFlow::Value::ValueType::UNINIT:
|
||||
ss << "Uninit";
|
||||
break;
|
||||
case ValueFlow::Value::ValueType::BUFFER_SIZE:
|
||||
case ValueFlow::Value::ValueType::CONTAINER_SIZE:
|
||||
ss << "size=" << this->intvalue;
|
||||
break;
|
||||
case ValueFlow::Value::ValueType::ITERATOR_START:
|
||||
ss << "start=" << this->intvalue;
|
||||
break;
|
||||
case ValueFlow::Value::ValueType::ITERATOR_END:
|
||||
ss << "end=" << this->intvalue;
|
||||
break;
|
||||
case ValueFlow::Value::ValueType::LIFETIME:
|
||||
ss << "lifetime[" << ValueFlow::Value::toString(this->lifetimeKind) << "]=("
|
||||
<< this->tokvalue->expressionString() << ")";
|
||||
break;
|
||||
case ValueFlow::Value::ValueType::SYMBOLIC:
|
||||
ss << "symbolic=(" << this->tokvalue->expressionString();
|
||||
if (this->intvalue > 0)
|
||||
ss << "+" << this->intvalue;
|
||||
else if (this->intvalue < 0)
|
||||
ss << "-" << -this->intvalue;
|
||||
ss << ")";
|
||||
break;
|
||||
}
|
||||
if (this->indirect > 0)
|
||||
for (int i = 0; i < this->indirect; i++)
|
||||
ss << "*";
|
||||
if (this->path > 0)
|
||||
ss << "@" << this->path;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::string ValueFlow::Value::infoString() const
|
||||
{
|
||||
switch (valueType) {
|
||||
|
@ -8509,6 +8595,8 @@ void ValueFlow::setValues(TokenList *tokenlist, SymbolDatabase* symboldatabase,
|
|||
}
|
||||
|
||||
valueFlowDynamicBufferSize(tokenlist, symboldatabase, settings);
|
||||
|
||||
valueFlowDebug(tokenlist, errorLogger);
|
||||
}
|
||||
|
||||
ValueFlow::Value ValueFlow::Value::unknown()
|
||||
|
|
|
@ -251,6 +251,8 @@ namespace ValueFlow {
|
|||
|
||||
std::string infoString() const;
|
||||
|
||||
std::string toString() const;
|
||||
|
||||
enum class ValueType {
|
||||
INT,
|
||||
TOK,
|
||||
|
|
Loading…
Reference in New Issue