Refactoring whole program analysis for CheckUninitVar and CheckNullPointer

This commit is contained in:
Daniel Marjamäki 2018-01-21 22:56:46 +01:00
parent 3159d151d3
commit 512b9f512c
4 changed files with 65 additions and 20 deletions

View File

@ -548,3 +548,18 @@ void CheckNullPointer::arithmeticError(const Token *tok, const ValueFlow::Value
value && value->isInconclusive()); value && value->isInconclusive());
} }
bool CheckNullPointer::isUnsafeFunction(const Scope *scope, int argnr, const Token **tok)
{
const Variable * const argvar = scope->function->getArgumentVar(argnr);
if (!argvar->isPointer())
return false;
for (const Token *tok2 = scope->classStart; tok2 != scope->classEnd; tok2 = tok2->next()) {
if (tok2->variable() != argvar)
continue;
if (!Token::Match(tok2->astParent(), "*|["))
return false;
*tok = tok2;
return true;
}
return false;
}

View File

@ -99,6 +99,8 @@ public:
nullPointerError(tok, "", &v, false); nullPointerError(tok, "", &v, false);
} }
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);
static bool isUnsafeFunction(const Scope *scope, int argnr, const Token **tok);
private: private:
/** Get error messages. Used by --errorlist */ /** Get error messages. Used by --errorlist */

View File

@ -1308,6 +1308,18 @@ std::string CheckUninitVar::MyFileInfo::toString() const
#define FUNCTION_ID(function) tokenizer->list.file(function->tokenDef) + ':' + MathLib::toString(function->tokenDef->linenr()) #define FUNCTION_ID(function) tokenizer->list.file(function->tokenDef) + ':' + MathLib::toString(function->tokenDef->linenr())
CheckUninitVar::MyFileInfo::FunctionArg::FunctionArg(const Tokenizer *tokenizer, const Scope *scope, unsigned int argnr_, const Token *tok)
:
id(FUNCTION_ID(scope->function)),
functionName(scope->className),
argnr(argnr_),
variableName(scope->function->getArgumentVar(argnr-1)->name())
{
location.fileName = tokenizer->list.file(tok);
location.linenr = tok->linenr();
}
Check::FileInfo *CheckUninitVar::getFileInfo(const Tokenizer *tokenizer, const Settings * /*settings*/) const Check::FileInfo *CheckUninitVar::getFileInfo(const Tokenizer *tokenizer, const Settings * /*settings*/) const
{ {
const SymbolDatabase * const symbolDatabase = tokenizer->getSymbolDatabase(); const SymbolDatabase * const symbolDatabase = tokenizer->getSymbolDatabase();
@ -1321,26 +1333,7 @@ Check::FileInfo *CheckUninitVar::getFileInfo(const Tokenizer *tokenizer, const S
continue; continue;
const Function *const function = scope->function; const Function *const function = scope->function;
// Unsafe arguments.. // function calls where uninitialized data is passed by address
for (int argnr = 0; argnr < function->argCount(); ++argnr) {
const Variable * const argvar = function->getArgumentVar(argnr);
if (!argvar->isPointer())
continue;
for (const Token *tok = scope->classStart; tok != scope->classEnd; tok = tok->next()) {
if (tok->variable() != argvar)
continue;
if (!Token::Match(tok->astParent(), "*|["))
break;
fileInfo->dereferenced.push_back(MyFileInfo::FunctionArg(FUNCTION_ID(function), scope->className, argnr+1, tokenizer->list.file(tok), tok->linenr(), argvar->name()));
while (Token::Match(tok->astParent(), "*|["))
tok = tok->astParent();
if (Token::Match(tok->astParent(),"%cop%"))
fileInfo->readData.push_back(MyFileInfo::FunctionArg(FUNCTION_ID(function), scope->className, argnr+1, tokenizer->list.file(tok), tok->linenr(), argvar->name()));
break;
}
}
// Unsafe calls..
for (const Token *tok = scope->classStart; tok != scope->classEnd; tok = tok->next()) { for (const Token *tok = scope->classStart; tok != scope->classEnd; tok = tok->next()) {
if (tok->str() != "(" || !tok->astOperand1() || !tok->astOperand2()) if (tok->str() != "(" || !tok->astOperand1() || !tok->astOperand2())
continue; continue;
@ -1371,11 +1364,40 @@ Check::FileInfo *CheckUninitVar::getFileInfo(const Tokenizer *tokenizer, const S
fileInfo->uninitialized.push_back(MyFileInfo::FunctionArg(FUNCTION_ID(tok->astOperand1()->function()), tok->astOperand1()->str(), argnr+1, tokenizer->list.file(argtok), argtok->linenr(), argtok->str())); fileInfo->uninitialized.push_back(MyFileInfo::FunctionArg(FUNCTION_ID(tok->astOperand1()->function()), tok->astOperand1()->str(), argnr+1, tokenizer->list.file(argtok), argtok->linenr(), argtok->str()));
} }
} }
// "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->readData.push_back(MyFileInfo::FunctionArg(tokenizer, &*scope, argnr+1, tok));
if (CheckNullPointer::isUnsafeFunction(&*scope, argnr, &tok))
fileInfo->dereferenced.push_back(MyFileInfo::FunctionArg(tokenizer, &*scope, argnr+1, tok));
}
} }
return fileInfo; return fileInfo;
} }
bool CheckUninitVar::isUnsafeFunction(const Scope *scope, int argnr, const Token **tok)
{
const Variable * const argvar = scope->function->getArgumentVar(argnr);
if (!argvar->isPointer())
return false;
for (const Token *tok2 = scope->classStart; tok2 != scope->classEnd; tok2 = tok2->next()) {
if (tok2->variable() != argvar)
continue;
if (!Token::Match(tok2->astParent(), "*|["))
return false;
while (Token::Match(tok2->astParent(), "*|["))
tok2 = tok2->astParent();
if (!Token::Match(tok2->astParent(),"%cop%"))
return false;
*tok = tok2;
return true;
}
return false;
}
Check::FileInfo * CheckUninitVar::loadFileInfoFromXml(const tinyxml2::XMLElement *xmlElement) const Check::FileInfo * CheckUninitVar::loadFileInfoFromXml(const tinyxml2::XMLElement *xmlElement) const
{ {
MyFileInfo *fileInfo = nullptr; MyFileInfo *fileInfo = nullptr;

View File

@ -100,6 +100,9 @@ public:
location.fileName = fileName; location.fileName = fileName;
location.linenr = linenr; location.linenr = linenr;
} }
FunctionArg(const Tokenizer *tokenizer, const Scope *scope, unsigned int argnr_, const Token *tok);
std::string id; std::string id;
std::string functionName; std::string functionName;
unsigned int argnr; unsigned int argnr;
@ -167,6 +170,9 @@ private:
"- using allocated data before it has been initialized\n" "- using allocated data before it has been initialized\n"
"- using dead pointer\n"; "- using dead pointer\n";
} }
static bool isUnsafeFunction(const Scope *scope, int argnr, const Token **tok);
}; };
/// @} /// @}
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------