CTU: Refactor isUnsafeFunction

This commit is contained in:
Daniel Marjamäki 2018-12-26 19:17:49 +01:00
parent a6e227a73c
commit a788512d66
5 changed files with 65 additions and 87 deletions

View File

@ -596,55 +596,20 @@ std::string CheckNullPointer::MyFileInfo::toString() const
return CTU::toString(unsafeUsage);
}
bool CheckNullPointer::isUnsafeFunction(const Scope *scope, int argnr, const Token **tok) const
static bool isUnsafeUsage(const Check *check, const Token *vartok)
{
const Variable * const argvar = scope->function->getArgumentVar(argnr);
if (!argvar->isPointer())
return false;
for (const Token *tok2 = scope->bodyStart; tok2 != scope->bodyEnd; tok2 = tok2->next()) {
if (Token::simpleMatch(tok2, ") {")) {
tok2 = tok2->linkAt(1);
if (Token::findmatch(tok2->link(), "return|throw", tok2))
return false;
if (isVariableChanged(tok2->link(), tok2, argvar->declarationId(), false, mSettings, mTokenizer->isCPP()))
return false;
}
if (tok2->variable() != argvar)
continue;
if (!Token::Match(tok2->astParent(), "*|["))
return false;
*tok = tok2;
return true;
}
return false;
(void)check;
return Token::Match(vartok->astParent(), "*|[");
}
Check::FileInfo *CheckNullPointer::getFileInfo(const Tokenizer *tokenizer, const Settings *settings) const
{
const CheckNullPointer checker(tokenizer, settings, nullptr);
return checker.getFileInfo();
}
Check::FileInfo *CheckNullPointer::getFileInfo() const
{
const SymbolDatabase * const symbolDatabase = mTokenizer->getSymbolDatabase();
const std::list<CTU::FileInfo::UnsafeUsage> &unsafeUsage = CTU::getUnsafeUsage(tokenizer, settings, nullptr, ::isUnsafeUsage);
if (unsafeUsage.empty())
return nullptr;
MyFileInfo *fileInfo = new MyFileInfo;
// Parse all functions in TU
for (const Scope &scope : symbolDatabase->scopeList) {
if (!scope.isExecutable() || scope.type != Scope::eFunction || !scope.function)
continue;
const Function *const function = scope.function;
// "Unsafe" functions unconditionally reads data before it is written..
for (int argnr = 0; argnr < function->argCount(); ++argnr) {
const Token *tok;
if (isUnsafeFunction(&scope, argnr, &tok))
fileInfo->unsafeUsage.push_back(CTU::FileInfo::UnsafeUsage(CTU::getFunctionId(mTokenizer, function), argnr+1, tok->str(), CTU::FileInfo::Location(mTokenizer,tok)));
}
}
fileInfo->unsafeUsage = unsafeUsage;
return fileInfo;
}

View File

@ -101,8 +101,6 @@ public:
}
void nullPointerError(const Token *tok, const std::string &varname, const ValueFlow::Value* value, bool inconclusive);
bool isUnsafeFunction(const Scope *scope, int argnr, const Token **tok) const;
/* data for multifile checking */
class MyFileInfo : public Check::FileInfo {
public:
@ -114,7 +112,7 @@ public:
};
/** @brief Parse current TU and extract file info */
Check::FileInfo *getFileInfo(const Tokenizer *tokenizer, const Settings *settings) const;
Check::FileInfo *getFileInfo(const Tokenizer *tokenizer, const Settings *settings) const override;
Check::FileInfo * loadFileInfoFromXml(const tinyxml2::XMLElement *xmlElement) const;
@ -122,8 +120,6 @@ public:
bool analyseWholeProgram(const CTU::FileInfo *ctu, const std::list<Check::FileInfo*> &fileInfo, const Settings& settings, ErrorLogger &errorLogger);
private:
Check::FileInfo *getFileInfo() const;
/** Get error messages. Used by --errorlist */
void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const override {
CheckNullPointer c(nullptr, settings, errorLogger);

View File

@ -1284,56 +1284,26 @@ std::string CheckUninitVar::MyFileInfo::toString() const
return CTU::toString(unsafeUsage);
}
bool CheckUninitVar::isUnsafeFunction(const Scope *scope, int argnr, const Token **tok) const
{
const Variable * const argvar = scope->function->getArgumentVar(argnr);
if (!argvar->isPointer())
return false;
for (const Token *tok2 = scope->bodyStart; tok2 != scope->bodyEnd; tok2 = tok2->next()) {
if (Token::simpleMatch(tok2, ") {")) {
tok2 = tok2->linkAt(1);
if (Token::findmatch(tok2->link(), "return|throw", tok2))
return false;
if (isVariableChanged(tok2->link(), tok2, argvar->declarationId(), false, mSettings, mTokenizer->isCPP()))
return false;
}
if (tok2->variable() != argvar)
continue;
if (!isVariableUsage(tok2, true, Alloc::ARRAY))
return false;
*tok = tok2;
return true;
}
return false;
}
Check::FileInfo *CheckUninitVar::getFileInfo(const Tokenizer *tokenizer, const Settings *settings) const
{
const CheckUninitVar checker(tokenizer, settings, nullptr);
return checker.getFileInfo();
}
static bool isVariableUsage(const Check *check, const Token *vartok)
{
const CheckUninitVar *c = dynamic_cast<const CheckUninitVar *>(check);
return c && c->isVariableUsage(vartok, true, CheckUninitVar::Alloc::ARRAY);
}
Check::FileInfo *CheckUninitVar::getFileInfo() const
{
const SymbolDatabase * const symbolDatabase = mTokenizer->getSymbolDatabase();
const std::list<CTU::FileInfo::UnsafeUsage> &unsafeUsage = CTU::getUnsafeUsage(mTokenizer, mSettings, this, ::isVariableUsage);
if (unsafeUsage.empty())
return nullptr;
MyFileInfo *fileInfo = new MyFileInfo;
// Parse all functions in TU
for (const Scope &scope : symbolDatabase->scopeList) {
if (!scope.isExecutable() || scope.type != Scope::eFunction || !scope.function)
continue;
const Function *const function = scope.function;
// "Unsafe" functions unconditionally reads data before it is written..
for (int argnr = 0; argnr < function->argCount(); ++argnr) {
const Token *tok;
if (isUnsafeFunction(&scope, argnr, &tok))
fileInfo->unsafeUsage.push_back(CTU::FileInfo::UnsafeUsage(CTU::getFunctionId(mTokenizer, function), argnr+1, tok->str(), CTU::FileInfo::Location(mTokenizer,tok)));
}
}
fileInfo->unsafeUsage = unsafeUsage ;
return fileInfo;
}

View File

@ -295,6 +295,51 @@ CTU::FileInfo *CTU::getFileInfo(const Tokenizer *tokenizer)
return fileInfo;
}
static bool isUnsafeFunction(const Tokenizer *tokenizer, const Settings *settings, const Scope *scope, int argnr, const Token **tok, const Check *check, bool (*isUnsafeUsage)(const Check *check, const Token *argtok))
{
const Variable * const argvar = scope->function->getArgumentVar(argnr);
if (!argvar->isPointer())
return false;
for (const Token *tok2 = scope->bodyStart; tok2 != scope->bodyEnd; tok2 = tok2->next()) {
if (Token::simpleMatch(tok2, ") {")) {
tok2 = tok2->linkAt(1);
if (Token::findmatch(tok2->link(), "return|throw", tok2))
return false;
if (isVariableChanged(tok2->link(), tok2, argvar->declarationId(), false, settings, tokenizer->isCPP()))
return false;
}
if (tok2->variable() != argvar)
continue;
if (!isUnsafeUsage(check, tok2))
return false;
*tok = tok2;
return true;
}
return false;
}
std::list<CTU::FileInfo::UnsafeUsage> CTU::getUnsafeUsage(const Tokenizer *tokenizer, const Settings *settings, const Check *check, bool (*isUnsafeUsage)(const Check *check, const Token *argtok))
{
std::list<CTU::FileInfo::UnsafeUsage> unsafeUsage;
// Parse all functions in TU
const SymbolDatabase * const symbolDatabase = tokenizer->getSymbolDatabase();
for (const Scope &scope : symbolDatabase->scopeList) {
if (!scope.isExecutable() || scope.type != Scope::eFunction || !scope.function)
continue;
const Function *const function = scope.function;
// "Unsafe" functions unconditionally reads data before it is written..
for (int argnr = 0; argnr < function->argCount(); ++argnr) {
const Token *tok;
if (isUnsafeFunction(tokenizer, settings, &scope, argnr, &tok, check, isUnsafeUsage))
unsafeUsage.push_back(CTU::FileInfo::UnsafeUsage(CTU::getFunctionId(tokenizer, function), argnr+1, tok->str(), CTU::FileInfo::Location(tokenizer,tok)));
}
}
return unsafeUsage;
}
static bool findPath(const CTU::FileInfo::FunctionCall &from,
const CTU::FileInfo::UnsafeUsage &to,

View File

@ -107,6 +107,8 @@ namespace CTU {
/** @brief Parse current TU and extract file info */
FileInfo *getFileInfo(const Tokenizer *tokenizer);
std::list<FileInfo::UnsafeUsage> getUnsafeUsage(const Tokenizer *tokenizer, const Settings *settings, const Check *check, bool (*isUnsafeUsage)(const Check *check, const Token *argtok));
std::list<FileInfo::UnsafeUsage> loadUnsafeUsageListFromXml(const tinyxml2::XMLElement *xmlElement);
}