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:
parent
c92230dfee
commit
40e5dab9dc
|
@ -450,7 +450,6 @@
|
||||||
|
|
||||||
<alloc init="false">malloc</alloc>
|
<alloc init="false">malloc</alloc>
|
||||||
<alloc init="true">calloc</alloc>
|
<alloc init="true">calloc</alloc>
|
||||||
<alloc init="true">realloc</alloc>
|
|
||||||
</memory>
|
</memory>
|
||||||
|
|
||||||
<resource>
|
<resource>
|
||||||
|
|
|
@ -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)
|
bool CheckMemoryLeakInFunction::notvar(const Token *tok, unsigned int varid, bool endpar)
|
||||||
{
|
{
|
||||||
const std::string end(endpar ? " &&|)" : " [;)&|]");
|
const std::string end(endpar ? " &&|)" : " [;)&|]");
|
||||||
|
@ -609,7 +570,7 @@ const char * CheckMemoryLeakInFunction::call_func(const Token *tok, std::list<co
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (noreturn.find(tok->str()) != noreturn.end() && tok->strAt(-1) != "=")
|
if (_settings->library.isnoreturn(tok->str()) && tok->strAt(-1) != "=")
|
||||||
return "exit";
|
return "exit";
|
||||||
|
|
||||||
if (varid > 0 && (getReallocationType(tok, varid) != No || getDeallocationType(tok, varid) != No))
|
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;
|
return nullptr;
|
||||||
|
|
||||||
// Function is not noreturn
|
// 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 nullptr;
|
||||||
|
|
||||||
return "callfunc";
|
return "callfunc";
|
||||||
|
@ -1309,7 +1274,7 @@ Token *CheckMemoryLeakInFunction::getcode(const Token *tok, std::list<const Toke
|
||||||
// just add a "::use"
|
// just add a "::use"
|
||||||
// The "::use" means that a member function was probably called but it wasn't analysed further
|
// The "::use" means that a member function was probably called but it wasn't analysed further
|
||||||
else if (classmember) {
|
else if (classmember) {
|
||||||
if (noreturn.find(tok->str()) != noreturn.end())
|
if (_settings->library.isnoreturn(tok->str()))
|
||||||
addtoken(&rettail, tok, "exit");
|
addtoken(&rettail, tok, "exit");
|
||||||
|
|
||||||
else if (!test_white_list_with_lib(tok->str(), _settings)) {
|
else if (!test_white_list_with_lib(tok->str(), _settings)) {
|
||||||
|
@ -2233,9 +2198,6 @@ static bool isInMemberFunc(const Scope* scope)
|
||||||
|
|
||||||
void CheckMemoryLeakInFunction::check()
|
void CheckMemoryLeakInFunction::check()
|
||||||
{
|
{
|
||||||
// fill the "noreturn"
|
|
||||||
parse_noreturn();
|
|
||||||
|
|
||||||
// Check locking/unlocking of global resources..
|
// Check locking/unlocking of global resources..
|
||||||
const std::size_t functions = symbolDatabase->functionScopes.size();
|
const std::size_t functions = symbolDatabase->functionScopes.size();
|
||||||
for (std::size_t i = 0; i < functions; ++i) {
|
for (std::size_t i = 0; i < functions; ++i) {
|
||||||
|
|
|
@ -296,9 +296,6 @@ public:
|
||||||
*/
|
*/
|
||||||
void checkScope(const Token *Tok1, const std::string &varname, unsigned int varid, bool classmember, unsigned int sz);
|
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:
|
private:
|
||||||
/** Report all possible errors (for the --errorlist) */
|
/** Report all possible errors (for the --errorlist) */
|
||||||
void getErrorMessages(ErrorLogger *e, const Settings *settings) const {
|
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";
|
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;
|
const SymbolDatabase *symbolDatabase;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -148,6 +148,7 @@ private:
|
||||||
|
|
||||||
|
|
||||||
void run() {
|
void run() {
|
||||||
|
LOAD_LIB_2(settings1.library, "std.cfg");
|
||||||
LOAD_LIB_2(settings1.library, "gtk.cfg");
|
LOAD_LIB_2(settings1.library, "gtk.cfg");
|
||||||
|
|
||||||
// Check that getcode works correctly..
|
// Check that getcode works correctly..
|
||||||
|
@ -366,7 +367,9 @@ private:
|
||||||
TEST_CASE(posixcfg);
|
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) {
|
std::string getcode(const char code[], const char varname[], bool classfunc=false) {
|
||||||
// Clear the error buffer..
|
// Clear the error buffer..
|
||||||
|
@ -374,6 +377,7 @@ private:
|
||||||
|
|
||||||
Settings settings;
|
Settings settings;
|
||||||
settings.standards.posix = true;
|
settings.standards.posix = true;
|
||||||
|
loadlib(settings.library);
|
||||||
|
|
||||||
// Tokenize..
|
// Tokenize..
|
||||||
Tokenizer tokenizer(&settings, this);
|
Tokenizer tokenizer(&settings, this);
|
||||||
|
@ -386,7 +390,6 @@ private:
|
||||||
|
|
||||||
// getcode..
|
// getcode..
|
||||||
CheckMemoryLeakInFunction checkMemoryLeak(&tokenizer, &settings, nullptr);
|
CheckMemoryLeakInFunction checkMemoryLeak(&tokenizer, &settings, nullptr);
|
||||||
checkMemoryLeak.parse_noreturn();
|
|
||||||
std::list<const Token *> callstack;
|
std::list<const Token *> callstack;
|
||||||
callstack.push_back(0);
|
callstack.push_back(0);
|
||||||
CheckMemoryLeak::AllocType allocType, deallocType;
|
CheckMemoryLeak::AllocType allocType, deallocType;
|
||||||
|
@ -539,9 +542,9 @@ private:
|
||||||
|
|
||||||
// exit..
|
// exit..
|
||||||
ASSERT_EQUALS(";;exit;", getcode("char *s; exit(0);", "s"));
|
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; 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"));
|
ASSERT_EQUALS(";;if{exit;}", getcode("char *s; if (a) { exit(0); }", "s"));
|
||||||
|
|
||||||
// list_for_each
|
// list_for_each
|
||||||
|
|
Loading…
Reference in New Issue