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);
- */
}