From c6924cc2872df825b59161b5d6930ad386e1a93a Mon Sep 17 00:00:00 2001 From: chrchr Date: Mon, 4 Dec 2023 12:15:10 +0100 Subject: [PATCH 01/10] Fix #2767 FP resourceLeak (regression) --- cfg/posix.cfg | 1 + lib/checkleakautovar.cpp | 3 +++ test/cfg/posix.c | 7 +++++++ 3 files changed, 11 insertions(+) diff --git a/cfg/posix.cfg b/cfg/posix.cfg index 25712fcebdd..73197fad4c1 100644 --- a/cfg/posix.cfg +++ b/cfg/posix.cfg @@ -6268,6 +6268,7 @@ The function 'mktemp' is considered to be dangerous due to race conditions and s openat socket close + fdopen opendir diff --git a/lib/checkleakautovar.cpp b/lib/checkleakautovar.cpp index 2f9f5909dd4..36dba1cd075 100644 --- a/lib/checkleakautovar.cpp +++ b/lib/checkleakautovar.cpp @@ -974,6 +974,9 @@ void CheckLeakAutoVar::functionCall(const Token *tokName, const Token *tokOpenin const Library::AllocFunc* deallocFunc = mSettings->library.getDeallocFuncInfo(tokName); VarInfo::AllocInfo dealloc(deallocFunc ? deallocFunc->groupId : 0, VarInfo::DEALLOC, tokName); if (const Library::AllocFunc* allocFunc = mSettings->library.getAllocFuncInfo(tokName)) { + if (mSettings->library.getDeallocFuncInfo(tokName)) { + changeAllocStatus(varInfo, dealloc.type == 0 ? allocation : dealloc, tokName, arg); + } if (allocFunc->arg == argNr && !(arg->variable() && arg->variable()->isArgument() && arg->valueType() && arg->valueType()->pointer > 1)) { leakIfAllocated(arg, varInfo); VarInfo::AllocInfo& varAlloc = varInfo.alloctype[arg->varId()]; diff --git a/test/cfg/posix.c b/test/cfg/posix.c index a163f4ed8fb..617d678125e 100644 --- a/test/cfg/posix.c +++ b/test/cfg/posix.c @@ -1113,6 +1113,13 @@ void resourceLeak_open2(void) // cppcheck-suppress resourceLeak } +void resourceLeak_fdopen(const char* fn) // #2767 +{ + int fi = open(fn, O_RDONLY); + FILE* fd = fdopen(fi, "r"); + fclose(fd); +} + void noleak(int x, int y, int z) { DIR *p1 = fdopendir(x); From 1481e167cf8867519a18b894d222dbdf429fd300 Mon Sep 17 00:00:00 2001 From: chrchr Date: Mon, 4 Dec 2023 12:21:24 +0100 Subject: [PATCH 02/10] Remove TODO, fix --- test/cfg/posix.c | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/test/cfg/posix.c b/test/cfg/posix.c index 617d678125e..31489299b2a 100644 --- a/test/cfg/posix.c +++ b/test/cfg/posix.c @@ -1060,6 +1060,13 @@ void resourceLeak_fdopen(int fd) // cppcheck-suppress resourceLeak } +void resourceLeak_fdopen2(const char* fn) // #2767 +{ + int fi = open(fn, O_RDONLY); + FILE* fd = fdopen(fi, "r"); + fclose(fd); +} + void resourceLeak_mkstemp(char *template) { // cppcheck-suppress unreadVariable @@ -1113,13 +1120,6 @@ void resourceLeak_open2(void) // cppcheck-suppress resourceLeak } -void resourceLeak_fdopen(const char* fn) // #2767 -{ - int fi = open(fn, O_RDONLY); - FILE* fd = fdopen(fi, "r"); - fclose(fd); -} - void noleak(int x, int y, int z) { DIR *p1 = fdopendir(x); @@ -1132,12 +1132,6 @@ void noleak(int x, int y, int z) close(fd1); int fd2 = open("a", O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); close(fd2); - /* TODO: add configuration for open/fdopen - // #2830 - int fd = open("path", O_RDONLY); - FILE *f = fdopen(fd, "rt"); - fclose(f); - */ } From 9f920257f305616cfb8099464e280ed76046b84c Mon Sep 17 00:00:00 2001 From: chrchr Date: Mon, 4 Dec 2023 14:51:05 +0100 Subject: [PATCH 03/10] Fix #12248 FP memleak when allocating struct member --- lib/checkleakautovar.cpp | 2 +- test/cfg/posix.c | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/lib/checkleakautovar.cpp b/lib/checkleakautovar.cpp index 36dba1cd075..35d5f4ee3b8 100644 --- a/lib/checkleakautovar.cpp +++ b/lib/checkleakautovar.cpp @@ -962,7 +962,7 @@ void CheckLeakAutoVar::functionCall(const Token *tokName, const Token *tokOpenin while (Token::Match(arg, "%name% .|:: %name%")) arg = arg->tokAt(2); - if (Token::Match(arg, "%var% [-,)] !!.") || Token::Match(arg, "& %var%")) { + if (Token::Match(arg, "%var% [-,)] !!.") || Token::Match(arg, "& %var% !!.")) { // goto variable if (arg->str() == "&") arg = arg->next(); diff --git a/test/cfg/posix.c b/test/cfg/posix.c index 31489299b2a..897d1e7927c 100644 --- a/test/cfg/posix.c +++ b/test/cfg/posix.c @@ -891,6 +891,22 @@ void validCode(va_list valist_arg1, va_list valist_arg2) } } +typedef struct { + size_t N; + int* data; +} S_memalign; + +S* posix_memalign_memleak(size_t n) { + S_memalign* s = malloc(sizeof(*s)); + s->N = n; + if (0 != posix_memalign((void**)&s->data, 16, n * sizeof(int))) { + free(s); + return NULL; + } + memset(s->data, 0, n * sizeof(int)); + return s; +} + ssize_t nullPointer_send(int socket, const void *buf, size_t len, int flags) { // cppcheck-suppress nullPointer From f13a4d52cc9ee0f30383eedc6bf158e7b1c86473 Mon Sep 17 00:00:00 2001 From: chrchr Date: Mon, 4 Dec 2023 15:27:40 +0100 Subject: [PATCH 04/10] Fix test --- test/cfg/posix.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/cfg/posix.c b/test/cfg/posix.c index 897d1e7927c..ff07ee5a85b 100644 --- a/test/cfg/posix.c +++ b/test/cfg/posix.c @@ -896,7 +896,7 @@ typedef struct { int* data; } S_memalign; -S* posix_memalign_memleak(size_t n) { +S_memalign* posix_memalign_memleak(size_t n) { S_memalign* s = malloc(sizeof(*s)); s->N = n; if (0 != posix_memalign((void**)&s->data, 16, n * sizeof(int))) { From ce880aca266593fe40191bcb26871d8207ecfa69 Mon Sep 17 00:00:00 2001 From: chrchr Date: Mon, 4 Dec 2023 17:37:54 +0100 Subject: [PATCH 05/10] Fix #12204 FP memleak when outparam allocation failed --- lib/checkleakautovar.cpp | 17 ++++++++++++++++- test/cfg/gnu.c | 11 +++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/lib/checkleakautovar.cpp b/lib/checkleakautovar.cpp index 35d5f4ee3b8..2af97678a5a 100644 --- a/lib/checkleakautovar.cpp +++ b/lib/checkleakautovar.cpp @@ -1123,11 +1123,26 @@ void CheckLeakAutoVar::ret(const Token *tok, VarInfo &varInfo, const bool isEndO const Token* const ifEnd = scope->bodyStart->previous(); const Token* const ifStart = ifEnd->link(); const Token* const alloc = it->second.allocTok; - if (precedes(ifStart, alloc) && succeeds(ifEnd, alloc)) { + if (precedes(ifStart, alloc) && succeeds(ifEnd, alloc)) { // allocation and check in if int argn{}; if (const Token* ftok = getTokenArgumentFunction(alloc, argn)) if (Token::Match(ftok->next()->astParent(), "%comp%")) continue; + } else { // allocation result assigned to variable + const Token* retAssign = it->second.allocTok->astParent(); + while (Token::Match(retAssign, "[&,(]")) + retAssign = retAssign->astParent(); + if (Token::simpleMatch(retAssign, "=") && retAssign->astOperand1()->varId()) { + bool isRetComp = false; + for (const Token* tok2 = ifStart; tok2 != ifEnd; tok2 = tok2->next()) { + if (tok2->varId() == retAssign->astOperand1()->varId()) { + isRetComp = true; + break; + } + } + if (isRetComp) + continue; + } } } diff --git a/test/cfg/gnu.c b/test/cfg/gnu.c index 35b65e816c7..d6682d04a23 100644 --- a/test/cfg/gnu.c +++ b/test/cfg/gnu.c @@ -364,6 +364,17 @@ void memleak_asprintf2() { // #12186 // cppcheck-suppress memleak } +void memleak_asprintf3(const char *fmt, const int arg) // #12204 +{ + char* ptr; + int ret = asprintf(&ptr, fmt, arg); + if (-1 == ret) { + return; + } + printf("%s", ptr); + free(ptr); +} + void memleak_asprintf3() { char* p = malloc(5); // cppcheck-suppress memleak From 771ad7459b17ad3d7c465396127f795962854598 Mon Sep 17 00:00:00 2001 From: chrchr Date: Mon, 4 Dec 2023 18:08:39 +0100 Subject: [PATCH 06/10] Fix --- lib/checkleakautovar.cpp | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/lib/checkleakautovar.cpp b/lib/checkleakautovar.cpp index 2af97678a5a..aefdff83c1c 100644 --- a/lib/checkleakautovar.cpp +++ b/lib/checkleakautovar.cpp @@ -1061,6 +1061,21 @@ void CheckLeakAutoVar::leakIfAllocated(const Token *vartok, } } +static const Token* getOutparamAllocation(const Token* tok, const Settings* settings) +{ + if (!tok) + return nullptr; + int argn{}; + const Token* ftok = getTokenArgumentFunction(tok, argn); + if (!ftok) + return nullptr; + if (const Library::AllocFunc* allocFunc = settings->library.getAllocFuncInfo(ftok)) { + if (allocFunc->arg == argn) + return ftok; + } + return nullptr; +} + void CheckLeakAutoVar::ret(const Token *tok, VarInfo &varInfo, const bool isEndOfScope) { const std::map &alloctype = varInfo.alloctype; @@ -1115,7 +1130,9 @@ void CheckLeakAutoVar::ret(const Token *tok, VarInfo &varInfo, const bool isEndO } // don't warn when returning after checking return value of outparam allocation - if (it->second.allocTok && (tok->scope()->type == Scope::ScopeType::eIf || tok->scope()->type== Scope::ScopeType::eElse)) { + const Token* outparamFunc{}; + if ((tok->scope()->type == Scope::ScopeType::eIf || tok->scope()->type== Scope::ScopeType::eElse) && + (outparamFunc = getOutparamAllocation(it->second.allocTok, mSettings))) { const Scope* scope = tok->scope(); if (scope->type == Scope::ScopeType::eElse) { scope = scope->bodyStart->tokAt(-2)->scope(); @@ -1124,12 +1141,10 @@ void CheckLeakAutoVar::ret(const Token *tok, VarInfo &varInfo, const bool isEndO const Token* const ifStart = ifEnd->link(); const Token* const alloc = it->second.allocTok; if (precedes(ifStart, alloc) && succeeds(ifEnd, alloc)) { // allocation and check in if - int argn{}; - if (const Token* ftok = getTokenArgumentFunction(alloc, argn)) - if (Token::Match(ftok->next()->astParent(), "%comp%")) - continue; + if (Token::Match(outparamFunc->next()->astParent(), "%comp%")) + continue; } else { // allocation result assigned to variable - const Token* retAssign = it->second.allocTok->astParent(); + const Token* retAssign = alloc->astParent(); while (Token::Match(retAssign, "[&,(]")) retAssign = retAssign->astParent(); if (Token::simpleMatch(retAssign, "=") && retAssign->astOperand1()->varId()) { From 3fc86d577d26b50b8be36cf078f796ee4a6b393c Mon Sep 17 00:00:00 2001 From: chrchr Date: Mon, 4 Dec 2023 18:10:14 +0100 Subject: [PATCH 07/10] Fix --- lib/checkleakautovar.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/checkleakautovar.cpp b/lib/checkleakautovar.cpp index aefdff83c1c..21c5cc939c5 100644 --- a/lib/checkleakautovar.cpp +++ b/lib/checkleakautovar.cpp @@ -1070,7 +1070,7 @@ static const Token* getOutparamAllocation(const Token* tok, const Settings* sett if (!ftok) return nullptr; if (const Library::AllocFunc* allocFunc = settings->library.getAllocFuncInfo(ftok)) { - if (allocFunc->arg == argn) + if (allocFunc->arg == argn + 1) return ftok; } return nullptr; From 3c947c41b7f9a21935c2388cb0679e48170abe96 Mon Sep 17 00:00:00 2001 From: chrchr Date: Mon, 4 Dec 2023 18:33:29 +0100 Subject: [PATCH 08/10] Fix test --- test/cfg/gnu.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/test/cfg/gnu.c b/test/cfg/gnu.c index d6682d04a23..e2ca818f938 100644 --- a/test/cfg/gnu.c +++ b/test/cfg/gnu.c @@ -364,17 +364,6 @@ void memleak_asprintf2() { // #12186 // cppcheck-suppress memleak } -void memleak_asprintf3(const char *fmt, const int arg) // #12204 -{ - char* ptr; - int ret = asprintf(&ptr, fmt, arg); - if (-1 == ret) { - return; - } - printf("%s", ptr); - free(ptr); -} - void memleak_asprintf3() { char* p = malloc(5); // cppcheck-suppress memleak @@ -409,6 +398,17 @@ void memleak_asprintf7(const char* fmt, const int arg) { return; } +void memleak_asprintf8(const char *fmt, const int arg) // #12204 +{ + char* ptr; + int ret = asprintf(&ptr, fmt, arg); + if (-1 == ret) { + return; + } + printf("%s", ptr); + free(ptr); +} + void memleak_xmalloc() { char *p = (char*)xmalloc(10); From 3d1838074346fc39531d5ea7de00c46550a6ff69 Mon Sep 17 00:00:00 2001 From: chrchr Date: Mon, 4 Dec 2023 19:19:30 +0100 Subject: [PATCH 09/10] Simplify --- lib/checkleakautovar.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/checkleakautovar.cpp b/lib/checkleakautovar.cpp index 21c5cc939c5..74230d14eaf 100644 --- a/lib/checkleakautovar.cpp +++ b/lib/checkleakautovar.cpp @@ -1144,9 +1144,7 @@ void CheckLeakAutoVar::ret(const Token *tok, VarInfo &varInfo, const bool isEndO if (Token::Match(outparamFunc->next()->astParent(), "%comp%")) continue; } else { // allocation result assigned to variable - const Token* retAssign = alloc->astParent(); - while (Token::Match(retAssign, "[&,(]")) - retAssign = retAssign->astParent(); + const Token* const retAssign = outparamFunc->next()->astParent(); if (Token::simpleMatch(retAssign, "=") && retAssign->astOperand1()->varId()) { bool isRetComp = false; for (const Token* tok2 = ifStart; tok2 != ifEnd; tok2 = tok2->next()) { From 3fce8cb215fadca1eb34c4c9f31d37f3494d8ca0 Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Tue, 5 Dec 2023 14:34:09 +0100 Subject: [PATCH 10/10] Format, comment --- test/cfg/posix.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/test/cfg/posix.c b/test/cfg/posix.c index ff07ee5a85b..474f160245b 100644 --- a/test/cfg/posix.c +++ b/test/cfg/posix.c @@ -896,15 +896,15 @@ typedef struct { int* data; } S_memalign; -S_memalign* posix_memalign_memleak(size_t n) { - S_memalign* s = malloc(sizeof(*s)); - s->N = n; - if (0 != posix_memalign((void**)&s->data, 16, n * sizeof(int))) { - free(s); - return NULL; - } - memset(s->data, 0, n * sizeof(int)); - return s; +S_memalign* posix_memalign_memleak(size_t n) { // #12248 + S_memalign* s = malloc(sizeof(*s)); + s->N = n; + if (0 != posix_memalign((void**)&s->data, 16, n * sizeof(int))) { + free(s); + return NULL; + } + memset(s->data, 0, n * sizeof(int)); + return s; } ssize_t nullPointer_send(int socket, const void *buf, size_t len, int flags)