CTU: Refactor isUnsafeFunction
This commit is contained in:
parent
a6e227a73c
commit
a788512d66
|
@ -596,55 +596,20 @@ std::string CheckNullPointer::MyFileInfo::toString() const
|
||||||
return CTU::toString(unsafeUsage);
|
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);
|
(void)check;
|
||||||
if (!argvar->isPointer())
|
return Token::Match(vartok->astParent(), "*|[");
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Check::FileInfo *CheckNullPointer::getFileInfo(const Tokenizer *tokenizer, const Settings *settings) const
|
Check::FileInfo *CheckNullPointer::getFileInfo(const Tokenizer *tokenizer, const Settings *settings) const
|
||||||
{
|
{
|
||||||
const CheckNullPointer checker(tokenizer, settings, nullptr);
|
const std::list<CTU::FileInfo::UnsafeUsage> &unsafeUsage = CTU::getUnsafeUsage(tokenizer, settings, nullptr, ::isUnsafeUsage);
|
||||||
return checker.getFileInfo();
|
if (unsafeUsage.empty())
|
||||||
}
|
return nullptr;
|
||||||
|
|
||||||
Check::FileInfo *CheckNullPointer::getFileInfo() const
|
|
||||||
{
|
|
||||||
const SymbolDatabase * const symbolDatabase = mTokenizer->getSymbolDatabase();
|
|
||||||
|
|
||||||
MyFileInfo *fileInfo = new MyFileInfo;
|
MyFileInfo *fileInfo = new MyFileInfo;
|
||||||
|
fileInfo->unsafeUsage = unsafeUsage;
|
||||||
// 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)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return fileInfo;
|
return fileInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -101,8 +101,6 @@ public:
|
||||||
}
|
}
|
||||||
void nullPointerError(const Token *tok, const std::string &varname, const ValueFlow::Value* value, bool inconclusive);
|
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 */
|
/* data for multifile checking */
|
||||||
class MyFileInfo : public Check::FileInfo {
|
class MyFileInfo : public Check::FileInfo {
|
||||||
public:
|
public:
|
||||||
|
@ -114,7 +112,7 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
/** @brief Parse current TU and extract file info */
|
/** @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;
|
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);
|
bool analyseWholeProgram(const CTU::FileInfo *ctu, const std::list<Check::FileInfo*> &fileInfo, const Settings& settings, ErrorLogger &errorLogger);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Check::FileInfo *getFileInfo() const;
|
|
||||||
|
|
||||||
/** Get error messages. Used by --errorlist */
|
/** Get error messages. Used by --errorlist */
|
||||||
void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const override {
|
void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const override {
|
||||||
CheckNullPointer c(nullptr, settings, errorLogger);
|
CheckNullPointer c(nullptr, settings, errorLogger);
|
||||||
|
|
|
@ -1284,56 +1284,26 @@ std::string CheckUninitVar::MyFileInfo::toString() const
|
||||||
return CTU::toString(unsafeUsage);
|
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
|
Check::FileInfo *CheckUninitVar::getFileInfo(const Tokenizer *tokenizer, const Settings *settings) const
|
||||||
{
|
{
|
||||||
const CheckUninitVar checker(tokenizer, settings, nullptr);
|
const CheckUninitVar checker(tokenizer, settings, nullptr);
|
||||||
return checker.getFileInfo();
|
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
|
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;
|
MyFileInfo *fileInfo = new MyFileInfo;
|
||||||
|
fileInfo->unsafeUsage = unsafeUsage ;
|
||||||
// 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)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return fileInfo;
|
return fileInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
45
lib/ctu.cpp
45
lib/ctu.cpp
|
@ -295,6 +295,51 @@ CTU::FileInfo *CTU::getFileInfo(const Tokenizer *tokenizer)
|
||||||
return fileInfo;
|
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,
|
static bool findPath(const CTU::FileInfo::FunctionCall &from,
|
||||||
const CTU::FileInfo::UnsafeUsage &to,
|
const CTU::FileInfo::UnsafeUsage &to,
|
||||||
|
|
|
@ -107,6 +107,8 @@ namespace CTU {
|
||||||
/** @brief Parse current TU and extract file info */
|
/** @brief Parse current TU and extract file info */
|
||||||
FileInfo *getFileInfo(const Tokenizer *tokenizer);
|
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);
|
std::list<FileInfo::UnsafeUsage> loadUnsafeUsageListFromXml(const tinyxml2::XMLElement *xmlElement);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue