diff --git a/cfg/posix.cfg b/cfg/posix.cfg index 25712fceb..73197fad4 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 bbfcd4e24..530e8c3df 100644 --- a/lib/checkleakautovar.cpp +++ b/lib/checkleakautovar.cpp @@ -967,7 +967,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(); @@ -979,6 +979,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()]; @@ -1063,6 +1066,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 + 1) + return ftok; + } + return nullptr; +} + void CheckLeakAutoVar::ret(const Token *tok, VarInfo &varInfo, const bool isEndOfScope) { const std::map &alloctype = varInfo.alloctype; @@ -1117,7 +1135,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(); @@ -1125,11 +1145,22 @@ 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)) { - int argn{}; - if (const Token* ftok = getTokenArgumentFunction(alloc, argn)) - if (Token::Match(ftok->next()->astParent(), "%comp%")) + if (precedes(ifStart, alloc) && succeeds(ifEnd, alloc)) { // allocation and check in if + if (Token::Match(outparamFunc->next()->astParent(), "%comp%")) + continue; + } else { // allocation result assigned to variable + 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()) { + 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 35b65e816..e2ca818f9 100644 --- a/test/cfg/gnu.c +++ b/test/cfg/gnu.c @@ -398,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); diff --git a/test/cfg/posix.c b/test/cfg/posix.c index a163f4ed8..474f16024 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_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) { // cppcheck-suppress nullPointer @@ -1060,6 +1076,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 @@ -1125,12 +1148,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); - */ }