diff --git a/cfg/windows.cfg b/cfg/windows.cfg index 48c1e9f2f84..105ee469b56 100644 --- a/cfg/windows.cfg +++ b/cfg/windows.cfg @@ -3699,7 +3699,7 @@ HFONT CreateFont( false - + @@ -3746,7 +3746,7 @@ HFONT CreateFont( false - + diff --git a/lib/checkmemoryleak.cpp b/lib/checkmemoryleak.cpp index b6f4dde5b41..93fbb3a4bb3 100644 --- a/lib/checkmemoryleak.cpp +++ b/lib/checkmemoryleak.cpp @@ -968,11 +968,13 @@ void CheckMemoryLeakNoVar::checkForUnreleasedInputArgument(const Scope *scope) if (Token::simpleMatch(tok->next()->astParent(), "(")) // passed to another function continue; - if (!tok->isKeyword() && (mSettings->library.isNotLibraryFunction(tok) || !mSettings->library.isLeakIgnore(functionName))) + if (!tok->isKeyword() && !tok->function() && !mSettings->library.isLeakIgnore(functionName)) continue; const std::vector args = getArguments(tok); + int argnr = -1; for (const Token* arg : args) { + ++argnr; if (arg->isOp() && !(tok->isKeyword() && arg->str() == "*")) // e.g. switch (*new int) continue; while (arg->astOperand1()) { @@ -983,10 +985,28 @@ void CheckMemoryLeakNoVar::checkForUnreleasedInputArgument(const Scope *scope) const AllocType alloc = getAllocationType(arg, 0); if (alloc == No) continue; - if ((alloc == New || alloc == NewArray) && arg->next() && !(arg->next()->isStandardType() || mSettings->library.detectContainerOrIterator(arg))) - continue; + if (alloc == New || alloc == NewArray) { + const Token* typeTok = arg->next(); + bool bail = !typeTok->isStandardType() && + !mSettings->library.detectContainerOrIterator(typeTok) && + !mSettings->library.podtype(typeTok->expressionString()); + if (bail && typeTok->type() && typeTok->type()->classScope && + typeTok->type()->classScope->numConstructors == 0 && + typeTok->type()->classScope->getDestructor() == nullptr) { + bail = false; + } + if (bail) + continue; + } if (isReopenStandardStream(arg)) continue; + if (tok->function()) { + const Variable* argvar = tok->function()->getArgumentVar(argnr); + if (!argvar || !argvar->valueType()) + continue; + if (argvar->valueType()->typeSize(mSettings->platform, /*p*/ true) >= mSettings->platform.sizeof_pointer) + continue; + } functionCallLeak(arg, arg->str(), functionName); } diff --git a/test/testmemleak.cpp b/test/testmemleak.cpp index beedd57b232..131116f5198 100644 --- a/test/testmemleak.cpp +++ b/test/testmemleak.cpp @@ -2456,6 +2456,43 @@ class TestMemleakNoVar : public TestFixture { " s->p = s->p ? strcpy(new char[N], s->p) : nullptr;\n" "};\n"); ASSERT_EQUALS("", errout.str()); + + check("struct S {};\n" // #11866 + "void f(bool b);\n" + "void g() {\n" + " f(new int());\n" + " f(new std::vector());\n" + " f(new S());\n" + " f(new tm());\n" + " f(malloc(sizeof(S)));\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:4]: (error) Allocation with new, f doesn't release it.\n" + "[test.cpp:5]: (error) Allocation with new, f doesn't release it.\n" + "[test.cpp:6]: (error) Allocation with new, f doesn't release it.\n" + "[test.cpp:7]: (error) Allocation with new, f doesn't release it.\n" + "[test.cpp:8]: (error) Allocation with malloc, f doesn't release it.\n", + errout.str()); + + check("void f(uintptr_t u);\n" + "void g() {\n" + " f((uintptr_t)new int());\n" + "}\n"); + ASSERT_EQUALS("", errout.str()); + + check("void f(uint8_t u);\n" + "void g() {\n" + " f((uint8_t)new int());\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:3]: (error) Allocation with new, f doesn't release it.\n", + errout.str()); + + check("void f(int i, T t);\n" + "void g(int i, U* u);\n" + "void h() {\n" + " f(1, new int());\n" + " g(1, new int());\n" + "}\n"); + ASSERT_EQUALS("", errout.str()); } void missingAssignment() {