Fix #9047 (c-style casts before malloc) (#1930)

* Fix #9047 (c-style casts before malloc)

Note that there are still no warnings for c++-style casts

* Fix memleak check with casts of assignments in if-statements

* Fix possible null pointer dereference

As pointed out by cppcheck.

* Add check of astOperand2 when removing casts

This is similar to how it is done in other checks.
This commit is contained in:
Rikard Falkeborn 2019-07-03 08:39:44 +02:00 committed by Daniel Marjamäki
parent c4933acb5a
commit 60a213e6a5
7 changed files with 55 additions and 12 deletions

View File

@ -65,12 +65,8 @@
<define name="G_TYPE_INSTANCE_GET_PRIVATE(instance, g_type, c_type)" value="((c_type*) g_type_instance_get_private ((GTypeInstance*) (instance), (g_type)))"/>
<define name="G_OBJECT(obj)" value="(GObject*)(obj)"/>
<define name="G_OBJECT_CLASS(class)" value="(G_TYPE_CHECK_CLASS_CAST ((class), G_TYPE_OBJECT, GObjectClass))"/>
<!-- TODO #9047: use this define instead of the one without the cast as soon as memleaks are detected also with the cast
<define name="_G_NEW(struct_type, n_structs, func)" value="((struct_type *) g_##func##_n ((n_structs), sizeof (struct_type)))"/> -->
<define name="_G_NEW(struct_type, n_structs, func)" value="(g_##func##_n ((n_structs), sizeof (struct_type)))"/>
<!-- TODO #9047: use this define instead of the one without the cast as soon as memleaks are detected also with the cast
<define name="_G_RENEW(struct_type, mem, n_structs, func)" value="((struct_type *) g_##func##_n (mem, (n_structs), sizeof (struct_type)))"/> -->
<define name="_G_RENEW(struct_type, mem, n_structs, func)" value="(g_##func##_n (mem, (n_structs), sizeof (struct_type)))"/>
<define name="_G_NEW(struct_type, n_structs, func)" value="((struct_type *) g_##func##_n ((n_structs), sizeof (struct_type)))"/>
<define name="_G_RENEW(struct_type, mem, n_structs, func)" value="((struct_type *) g_##func##_n (mem, (n_structs), sizeof (struct_type)))"/>
<define name="g_new(struct_type, n_structs)" value="_G_NEW (struct_type, n_structs, malloc)"/>
<define name="g_new0(struct_type, n_structs)" value="_G_NEW (struct_type, n_structs, malloc0)"/>
<define name="g_renew(struct_type, mem, n_structs)" value="_G_RENEW (struct_type, mem, n_structs, realloc)"/>

View File

@ -301,7 +301,9 @@ void CheckLeakAutoVar::checkScope(const Token * const startToken,
}
// right ast part (after `=` operator)
const Token* const tokRightAstOperand = tokAssignOp->astOperand2();
const Token* tokRightAstOperand = tokAssignOp->astOperand2();
while (tokRightAstOperand && tokRightAstOperand->isCast())
tokRightAstOperand = tokRightAstOperand->astOperand2() ? tokRightAstOperand->astOperand2() : tokRightAstOperand->astOperand1();
// is variable used in rhs?
if (isVarUsedInTree(tokRightAstOperand, varTok->varId()))
@ -368,8 +370,12 @@ void CheckLeakAutoVar::checkScope(const Token * const startToken,
if (Token::Match(innerTok, "%var% =") && innerTok->astParent() == innerTok->next()) {
// allocation?
if (Token::Match(innerTok->tokAt(2), "%type% (")) {
const Library::AllocFunc* f = mSettings->library.alloc(innerTok->tokAt(2));
// right ast part (after `=` operator)
const Token* tokRightAstOperand = innerTok->next()->astOperand2();
while (tokRightAstOperand && tokRightAstOperand->isCast())
tokRightAstOperand = tokRightAstOperand->astOperand2() ? tokRightAstOperand->astOperand2() : tokRightAstOperand->astOperand1();
if (tokRightAstOperand && Token::Match(tokRightAstOperand->previous(), "%type% (")) {
const Library::AllocFunc* f = mSettings->library.alloc(tokRightAstOperand->previous());
if (f && f->arg == -1) {
VarInfo::AllocInfo& varAlloc = alloctype[innerTok->varId()];
varAlloc.type = f->groupId;

View File

@ -79,7 +79,7 @@ void ignoreleak(void)
{
char *p = (char *)malloc(10);
__builtin_memset(&(p[0]), 0, 10);
// TODO // cppcheck-suppress memleak
// cppcheck-suppress memleak
}
void memleak_asprintf(char **ptr, const char *fmt, const int arg)

View File

@ -107,6 +107,19 @@ void g_new_test()
// cppcheck-suppress memleak
}
void g_new_if_test()
{
struct a {
int b;
};
struct a * pNew3;
if (pNew3 = g_new(struct a, 6)) {
printf("%p", pNew3);
}
// cppcheck-suppress memleak
}
void g_try_new0_test()
{
struct a {

View File

@ -117,7 +117,7 @@ void ignoreleak(void)
{
char *p = (char *)malloc(10);
memset(&(p[0]), 0, 10);
// TODO cppcheck-suppress memleak
// cppcheck-suppress memleak
}
// null pointer

View File

@ -379,7 +379,7 @@ void memleak_LocalAlloc()
(void)LocalFlags(pszBuf);
LocalLock(pszBuf);
LocalUnlock(pszBuf);
// TODO cppcheck-suppress memleak
// cppcheck-suppress memleak
}
void resourceLeak_CreateSemaphoreA()

View File

@ -60,6 +60,8 @@ private:
TEST_CASE(assign14);
TEST_CASE(assign15);
TEST_CASE(assign16);
TEST_CASE(assign17); // #9047
TEST_CASE(assign18);
TEST_CASE(deallocuse1);
TEST_CASE(deallocuse2);
@ -322,6 +324,32 @@ private:
ASSERT_EQUALS("", errout.str());
}
void assign17() { // #9047
check("void f() {\n"
" char *p = (char*)malloc(10);\n"
"}");
ASSERT_EQUALS("[test.c:3]: (error) Memory leak: p\n", errout.str());
check("void f() {\n"
" char *p = (char*)(int*)malloc(10);\n"
"}");
ASSERT_EQUALS("[test.c:3]: (error) Memory leak: p\n", errout.str());
}
void assign18() {
check("void f(int x) {\n"
" char *p;\n"
" if (x && (p = (char*)malloc(10))) { }"
"}");
ASSERT_EQUALS("[test.c:3]: (error) Memory leak: p\n", errout.str());
check("void f(int x) {\n"
" char *p;\n"
" if (x && (p = (char*)(int*)malloc(10))) { }"
"}");
ASSERT_EQUALS("[test.c:3]: (error) Memory leak: p\n", errout.str());
}
void deallocuse1() {
check("void f(char *p) {\n"
" free(p);\n"