Refactorization in checkmemoryleak.cpp:

- Use Library to detect noreturn/notnoreturn functions
- Removed realloc from std.cfg as long as there is no proper way to configure such functions
This commit is contained in:
PKEuS 2014-09-01 13:54:33 +02:00
parent c92230dfee
commit 40e5dab9dc
4 changed files with 14 additions and 59 deletions

View File

@ -450,7 +450,6 @@
<alloc init="false">malloc</alloc>
<alloc init="true">calloc</alloc>
<alloc init="true">realloc</alloc>
</memory>
<resource>

View File

@ -506,45 +506,6 @@ const char *CheckMemoryLeak::functionArgAlloc(const Function *func, unsigned int
}
void CheckMemoryLeakInFunction::parse_noreturn()
{
if (noreturn.empty()) {
noreturn.insert("exit");
noreturn.insert("_exit");
noreturn.insert("_Exit");
noreturn.insert("abort");
noreturn.insert("err");
noreturn.insert("verr");
noreturn.insert("errx");
noreturn.insert("verrx");
noreturn.insert("ExitProcess");
noreturn.insert("ExitThread");
noreturn.insert("pthread_exit");
}
// only check functions
const std::size_t functionsCount = symbolDatabase->functionScopes.size();
for (std::size_t i = 0; i < functionsCount; ++i) {
const Scope * scope = symbolDatabase->functionScopes[i];
// parse this function to check if it contains an "exit" call..
bool isNoreturn = false;
for (const Token *tok2 = scope->classStart->next(); tok2 != scope->classEnd; tok2 = tok2->next()) {
if (Token::Match(tok2->previous(), "[;{}] exit (")) {
isNoreturn = true;
break;
}
}
// This function is not a noreturn function
if (isNoreturn)
noreturn.insert(scope->className);
else
notnoreturn.insert(scope->className);
}
}
bool CheckMemoryLeakInFunction::notvar(const Token *tok, unsigned int varid, bool endpar)
{
const std::string end(endpar ? " &&|)" : " [;)&|]");
@ -609,7 +570,7 @@ const char * CheckMemoryLeakInFunction::call_func(const Token *tok, std::list<co
return 0;
}
if (noreturn.find(tok->str()) != noreturn.end() && tok->strAt(-1) != "=")
if (_settings->library.isnoreturn(tok->str()) && tok->strAt(-1) != "=")
return "exit";
if (varid > 0 && (getReallocationType(tok, varid) != No || getDeallocationType(tok, varid) != No))
@ -650,7 +611,11 @@ const char * CheckMemoryLeakInFunction::call_func(const Token *tok, std::list<co
return nullptr;
// Function is not noreturn
if (notnoreturn.find(funcname) != notnoreturn.end())
if (tok->function()) {
std::string temp;
if (!_settings->library.isScopeNoReturn(tok->function()->functionScope->classEnd, &temp) && temp.empty())
return nullptr;
} else if (_settings->library.isnotnoreturn(funcname))
return nullptr;
return "callfunc";
@ -1309,7 +1274,7 @@ Token *CheckMemoryLeakInFunction::getcode(const Token *tok, std::list<const Toke
// just add a "::use"
// The "::use" means that a member function was probably called but it wasn't analysed further
else if (classmember) {
if (noreturn.find(tok->str()) != noreturn.end())
if (_settings->library.isnoreturn(tok->str()))
addtoken(&rettail, tok, "exit");
else if (!test_white_list_with_lib(tok->str(), _settings)) {
@ -2233,9 +2198,6 @@ static bool isInMemberFunc(const Scope* scope)
void CheckMemoryLeakInFunction::check()
{
// fill the "noreturn"
parse_noreturn();
// Check locking/unlocking of global resources..
const std::size_t functions = symbolDatabase->functionScopes.size();
for (std::size_t i = 0; i < functions; ++i) {

View File

@ -296,9 +296,6 @@ public:
*/
void checkScope(const Token *Tok1, const std::string &varname, unsigned int varid, bool classmember, unsigned int sz);
/** parse tokens to see what functions are "noreturn" */
void parse_noreturn();
private:
/** Report all possible errors (for the --errorlist) */
void getErrorMessages(ErrorLogger *e, const Settings *settings) const {
@ -331,12 +328,6 @@ private:
return "Is there any allocated memory when a function goes out of scope\n";
}
/** Function names for functions that are "noreturn" */
std::set<std::string> noreturn;
/** Function names for functions that are not "noreturn" */
std::set<std::string> notnoreturn;
const SymbolDatabase *symbolDatabase;
};

View File

@ -148,6 +148,7 @@ private:
void run() {
LOAD_LIB_2(settings1.library, "std.cfg");
LOAD_LIB_2(settings1.library, "gtk.cfg");
// Check that getcode works correctly..
@ -366,7 +367,9 @@ private:
TEST_CASE(posixcfg);
}
void loadlib(Library& library) {
LOAD_LIB_2(library, "std.cfg");
}
std::string getcode(const char code[], const char varname[], bool classfunc=false) {
// Clear the error buffer..
@ -374,6 +377,7 @@ private:
Settings settings;
settings.standards.posix = true;
loadlib(settings.library);
// Tokenize..
Tokenizer tokenizer(&settings, this);
@ -386,7 +390,6 @@ private:
// getcode..
CheckMemoryLeakInFunction checkMemoryLeak(&tokenizer, &settings, nullptr);
checkMemoryLeak.parse_noreturn();
std::list<const Token *> callstack;
callstack.push_back(0);
CheckMemoryLeak::AllocType allocType, deallocType;
@ -539,9 +542,9 @@ private:
// exit..
ASSERT_EQUALS(";;exit;", getcode("char *s; exit(0);", "s"));
ASSERT_EQUALS(";;exit;", getcode("char *s; _exit(0);", "s"));
ASSERT_EQUALS(";;callfunc;", getcode("char *s; _exit(0);", "s")); // not in std.cfg nor in gtk.cfg
ASSERT_EQUALS(";;exit;", getcode("char *s; abort();", "s"));
ASSERT_EQUALS(";;exit;", getcode("char *s; err(0);", "s"));
ASSERT_EQUALS(";;callfunc;", getcode("char *s; err(0);", "s")); // not in std.cfg nor in gtk.cfg
ASSERT_EQUALS(";;if{exit;}", getcode("char *s; if (a) { exit(0); }", "s"));
// list_for_each