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:
Paul Fultz II 2022-05-31 23:53:21 -05:00 committed by GitHub
parent 703396e549
commit e430a11b49
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 156 additions and 70 deletions

View File

@ -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)

View File

@ -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);

View File

@ -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()) {

View File

@ -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.

View File

@ -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, "(|[|{"))

View File

@ -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()

View File

@ -251,6 +251,8 @@ namespace ValueFlow {
std::string infoString() const;
std::string toString() const;
enum class ValueType {
INT,
TOK,