Fixed #4867 (Memory Leak: Return value of malloc)
This commit is contained in:
parent
b411efa33f
commit
7a6386bc4b
|
@ -2702,6 +2702,9 @@ void CheckMemoryLeakNoVar::check()
|
||||||
for (std::size_t i = 0; i < functions; ++i) {
|
for (std::size_t i = 0; i < functions; ++i) {
|
||||||
const Scope * scope = symbolDatabase->functionScopes[i];
|
const Scope * scope = symbolDatabase->functionScopes[i];
|
||||||
|
|
||||||
|
// Checks if a call to an allocation function like malloc() is made and its return value is not assigned.
|
||||||
|
checkForUnusedReturnValue(scope);
|
||||||
|
|
||||||
// goto the "}" that ends the executable scope..
|
// goto the "}" that ends the executable scope..
|
||||||
const Token *tok = scope->classEnd;
|
const Token *tok = scope->classEnd;
|
||||||
|
|
||||||
|
@ -2743,7 +2746,27 @@ void CheckMemoryLeakNoVar::check()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// Checks if a call to an allocation function like malloc() is made and its return value is not assigned.
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
void CheckMemoryLeakNoVar::checkForUnusedReturnValue(const Scope *scope)
|
||||||
|
{
|
||||||
|
for (const Token *tok = scope->classStart; tok != scope->classEnd; tok = tok->next()) {
|
||||||
|
if (Token::Match(tok, "{|}|; %var% (")) {
|
||||||
|
tok = tok->next();
|
||||||
|
const int allocationId = _settings->library.alloc(tok->str());
|
||||||
|
if (allocationId > 0)
|
||||||
|
returnValueNotUsedError(tok, tok->str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void CheckMemoryLeakNoVar::functionCallLeak(const Token *loc, const std::string &alloc, const std::string &functionCall)
|
void CheckMemoryLeakNoVar::functionCallLeak(const Token *loc, const std::string &alloc, const std::string &functionCall)
|
||||||
{
|
{
|
||||||
reportError(loc, Severity::error, "leakNoVarFunctionCall", "Allocation with " + alloc + ", " + functionCall + " doesn't release it.");
|
reportError(loc, Severity::error, "leakNoVarFunctionCall", "Allocation with " + alloc + ", " + functionCall + " doesn't release it.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CheckMemoryLeakNoVar::returnValueNotUsedError(const Token *tok, const std::string &alloc)
|
||||||
|
{
|
||||||
|
reportError(tok, Severity::error, "leakReturnValNotUsed", "Return value of allocation function " + alloc + " is not used.");
|
||||||
|
}
|
||||||
|
|
|
@ -449,13 +449,20 @@ public:
|
||||||
void check();
|
void check();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
/**
|
||||||
|
* @brief %Check if a call to an allocation function like malloc() is made and its return value is not assigned.
|
||||||
|
* @param scope The scope of the function to check.
|
||||||
|
*/
|
||||||
|
void checkForUnusedReturnValue(const Scope *scope);
|
||||||
|
|
||||||
void functionCallLeak(const Token *loc, const std::string &alloc, const std::string &functionCall);
|
void functionCallLeak(const Token *loc, const std::string &alloc, const std::string &functionCall);
|
||||||
|
void returnValueNotUsedError(const Token* tok, const std::string &alloc);
|
||||||
|
|
||||||
void getErrorMessages(ErrorLogger *e, const Settings *settings) const {
|
void getErrorMessages(ErrorLogger *e, const Settings *settings) const {
|
||||||
CheckMemoryLeakNoVar c(0, settings, e);
|
CheckMemoryLeakNoVar c(0, settings, e);
|
||||||
|
|
||||||
c.functionCallLeak(0, "funcName", "funcName");
|
c.functionCallLeak(0, "funcName", "funcName");
|
||||||
|
c.returnValueNotUsedError(0, "funcName");
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string myName() {
|
static std::string myName() {
|
||||||
|
|
|
@ -1053,15 +1053,6 @@ private:
|
||||||
ASSERT_EQUALS("[test.cpp:5]: (error) Memory leak: str\n", errout.str());
|
ASSERT_EQUALS("[test.cpp:5]: (error) Memory leak: str\n", errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void ifelse6() {
|
void ifelse6() {
|
||||||
check("static char *f()\n"
|
check("static char *f()\n"
|
||||||
"{\n"
|
"{\n"
|
||||||
|
@ -5495,6 +5486,16 @@ private:
|
||||||
Settings settings;
|
Settings settings;
|
||||||
settings.standards.posix = true;
|
settings.standards.posix = true;
|
||||||
|
|
||||||
|
// Add some test allocation functions to the library.
|
||||||
|
// When not run as a unit test, these are read from
|
||||||
|
// an XML file (e.g. cfg/posix.cfg).
|
||||||
|
int id = 0;
|
||||||
|
while (!settings.library.ismemory(++id))
|
||||||
|
continue;
|
||||||
|
settings.library.setalloc("malloc", id);
|
||||||
|
settings.library.setalloc("calloc", id);
|
||||||
|
settings.library.setalloc("strdup", id);
|
||||||
|
|
||||||
// Tokenize..
|
// Tokenize..
|
||||||
Tokenizer tokenizer(&settings, this);
|
Tokenizer tokenizer(&settings, this);
|
||||||
std::istringstream istr(code);
|
std::istringstream istr(code);
|
||||||
|
@ -5510,7 +5511,7 @@ private:
|
||||||
// pass allocated memory to function..
|
// pass allocated memory to function..
|
||||||
TEST_CASE(functionParameter);
|
TEST_CASE(functionParameter);
|
||||||
// never use leakable resource
|
// never use leakable resource
|
||||||
TEST_CASE(missingAssignement);
|
TEST_CASE(missingAssignment);
|
||||||
}
|
}
|
||||||
|
|
||||||
void functionParameter() {
|
void functionParameter() {
|
||||||
|
@ -5549,11 +5550,43 @@ private:
|
||||||
TODO_ASSERT_EQUALS("[test.cpp:4]: (error) Allocation with strdup, mkstemp doesn't release it.\n", "", errout.str());
|
TODO_ASSERT_EQUALS("[test.cpp:4]: (error) Allocation with strdup, mkstemp doesn't release it.\n", "", errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void missingAssignement() {
|
void missingAssignment() {
|
||||||
check("void x()\n"
|
check("void x()\n"
|
||||||
"{\n"
|
"{\n"
|
||||||
" malloc(10);\n"
|
" malloc(10);\n"
|
||||||
"}");
|
"}");
|
||||||
|
ASSERT_EQUALS("[test.cpp:3]: (error) Return value of allocation function malloc is not used.\n", errout.str());
|
||||||
|
|
||||||
|
check("void x()\n"
|
||||||
|
"{\n"
|
||||||
|
" calloc(10);\n"
|
||||||
|
"}");
|
||||||
|
ASSERT_EQUALS("[test.cpp:3]: (error) Return value of allocation function calloc is not used.\n", errout.str());
|
||||||
|
|
||||||
|
check("void x()\n"
|
||||||
|
"{\n"
|
||||||
|
" strdup(\"Test\");\n"
|
||||||
|
"}");
|
||||||
|
ASSERT_EQUALS("[test.cpp:3]: (error) Return value of allocation function strdup is not used.\n", errout.str());
|
||||||
|
|
||||||
|
check("void x()\n"
|
||||||
|
"{\n"
|
||||||
|
" (char*) malloc(10);\n"
|
||||||
|
"}");
|
||||||
|
ASSERT_EQUALS("[test.cpp:3]: (error) Return value of allocation function malloc is not used.\n", errout.str());
|
||||||
|
|
||||||
|
check("void x()\n"
|
||||||
|
"{\n"
|
||||||
|
" char* ptr = malloc(10);\n"
|
||||||
|
" foo(ptr);\n"
|
||||||
|
" free(ptr);\n"
|
||||||
|
"}");
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
|
check("void x()\n"
|
||||||
|
"{\n"
|
||||||
|
" 42,malloc(42);\n"
|
||||||
|
"}");
|
||||||
TODO_ASSERT_EQUALS("[test.cpp:3]: (error) Return value of allocation function malloc is not used.\n", "", errout.str());
|
TODO_ASSERT_EQUALS("[test.cpp:3]: (error) Return value of allocation function malloc is not used.\n", "", errout.str());
|
||||||
|
|
||||||
check("void *f()\n"
|
check("void *f()\n"
|
||||||
|
|
Loading…
Reference in New Issue