From 143a0e64be084180d89da8a35c37688b6e5b34d8 Mon Sep 17 00:00:00 2001 From: chrchr Date: Mon, 11 Dec 2023 15:36:58 +0100 Subject: [PATCH 01/10] Fix #10905, #11665 FN deallocuse --- lib/checkleakautovar.cpp | 20 ++++++-------------- test/testleakautovar.cpp | 28 ++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 14 deletions(-) diff --git a/lib/checkleakautovar.cpp b/lib/checkleakautovar.cpp index 530e8c3df62..956bdc91bba 100644 --- a/lib/checkleakautovar.cpp +++ b/lib/checkleakautovar.cpp @@ -466,6 +466,7 @@ bool CheckLeakAutoVar::checkScope(const Token * const startToken, const Token * closingParenthesis = tok->linkAt(1); for (const Token *innerTok = tok->tokAt(2); innerTok && innerTok != closingParenthesis; innerTok = innerTok->next()) { // TODO: replace with checkTokenInsideExpression() + checkTokenInsideExpression(innerTok, varInfo); if (!isLocalVarNoAutoDealloc(innerTok, mTokenizer->isCPP())) continue; @@ -500,16 +501,6 @@ bool CheckLeakAutoVar::checkScope(const Token * const startToken, varAlloc.allocTok = innerTok->tokAt(2); } } - - // check for function call - const Token * const openingPar = isFunctionCall(innerTok); - if (openingPar) { - const Library::AllocFunc* allocFunc = mSettings->library.getDeallocFuncInfo(innerTok); - // innerTok is a function name - const VarInfo::AllocInfo allocation(0, VarInfo::NOALLOC); - functionCall(innerTok, openingPar, varInfo, allocation, allocFunc); - innerTok = openingPar->link(); - } } if (Token::simpleMatch(closingParenthesis, ") {")) { @@ -688,14 +679,14 @@ bool CheckLeakAutoVar::checkScope(const Token * const startToken, continue; functionCall(ftok, openingPar, varInfo, allocation, af); - tok = ftok->next()->link(); + const Token* endPar = ftok->next()->link(); // Handle scopes that might be noreturn - if (allocation.status == VarInfo::NOALLOC && Token::simpleMatch(tok, ") ; }")) { + if (allocation.status == VarInfo::NOALLOC && Token::simpleMatch(endPar, ") ; }")) { if (ftok->isKeyword()) continue; bool unknown = false; - if (mTokenizer->isScopeNoReturn(tok->tokAt(2), &unknown)) { + if (mTokenizer->isScopeNoReturn(endPar->tokAt(2), &unknown)) { if (!unknown) varInfo.clear(); else { @@ -805,7 +796,8 @@ bool CheckLeakAutoVar::checkScope(const Token * const startToken, const Token * vtok = typeEndTok->tokAt(3); const VarInfo::AllocInfo allocation(af ? af->groupId : (arrayDelete ? NEW_ARRAY : NEW), VarInfo::OWNED, ftok); changeAllocStatus(varInfo, allocation, vtok, vtok); - } + } else if (Token::Match(tok, "%var% .")) + checkTokenInsideExpression(tok, varInfo); } ret(endToken, varInfo, true); return true; diff --git a/test/testleakautovar.cpp b/test/testleakautovar.cpp index ed6983ec3ea..adf60b1c4ab 100644 --- a/test/testleakautovar.cpp +++ b/test/testleakautovar.cpp @@ -112,6 +112,7 @@ class TestLeakAutoVar : public TestFixture { TEST_CASE(deallocuse11); // #8302 TEST_CASE(deallocuse12); TEST_CASE(deallocuse13); + TEST_CASE(deallocuse14); TEST_CASE(doublefree1); TEST_CASE(doublefree2); @@ -924,6 +925,33 @@ class TestLeakAutoVar : public TestFixture { errout.str()); } + void deallocuse14() { + check("struct S { void f(); };\n" // #10905 + "void g() {\n" + " S* s = new S;\n" + " delete s;\n" + " s->f();\n" + "}\n", true); + ASSERT_EQUALS("[test.cpp:5]: (error) Dereferencing 's' after it is deallocated / released\n", + errout.str()); + + const Settings s = settingsBuilder().library("std.cfg").build(); + check("void f(char *p, const char *q) {\n" // #11665 + " free(p);\n" + " strcpy(p, q);\n" + "}\n", false, &s); + ASSERT_EQUALS("[test.c:3]: (error) Dereferencing 'p' after it is deallocated / released\n", + errout.str()); + + check("void f() {\n" + " int *p = (int*)malloc(4);\n" + " free(p);\n" + " if (*p == 5) {}\n" + "}\n"); + ASSERT_EQUALS("[test.c:4]: (error) Dereferencing 'p' after it is deallocated / released\n", + errout.str()); + } + void doublefree1() { // #3895 check("void f(char *p) {\n" " if (x)\n" From 2f7a426d46622d7fef47348cb10e7debb061bb44 Mon Sep 17 00:00:00 2001 From: chrchr Date: Mon, 11 Dec 2023 16:32:23 +0100 Subject: [PATCH 02/10] Fix --- lib/checkleakautovar.cpp | 4 +++- test/testleakautovar.cpp | 6 ++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/checkleakautovar.cpp b/lib/checkleakautovar.cpp index 956bdc91bba..6e0357a3f6c 100644 --- a/lib/checkleakautovar.cpp +++ b/lib/checkleakautovar.cpp @@ -679,7 +679,9 @@ bool CheckLeakAutoVar::checkScope(const Token * const startToken, continue; functionCall(ftok, openingPar, varInfo, allocation, af); - const Token* endPar = ftok->next()->link(); + const Token* const endPar = ftok->next()->link(); + if (af) + tok = endPar; // Handle scopes that might be noreturn if (allocation.status == VarInfo::NOALLOC && Token::simpleMatch(endPar, ") ; }")) { diff --git a/test/testleakautovar.cpp b/test/testleakautovar.cpp index adf60b1c4ab..81c3debd83d 100644 --- a/test/testleakautovar.cpp +++ b/test/testleakautovar.cpp @@ -943,6 +943,12 @@ class TestLeakAutoVar : public TestFixture { ASSERT_EQUALS("[test.c:3]: (error) Dereferencing 'p' after it is deallocated / released\n", errout.str()); + check("void f(const char* fn, const char* m) {\n" + " FILE* fp = fopen(fn, m);\n" + " fclose(fp);\n" + "}\n", false, &s); + ASSERT_EQUALS("", errout.str()); + check("void f() {\n" " int *p = (int*)malloc(4);\n" " free(p);\n" From 0e7d96f0db2a93d0f7a365a62dc81379ce22927f Mon Sep 17 00:00:00 2001 From: chrchr Date: Mon, 11 Dec 2023 17:14:36 +0100 Subject: [PATCH 03/10] Undo --- lib/checkleakautovar.cpp | 8 +++----- test/testleakautovar.cpp | 11 +++-------- 2 files changed, 6 insertions(+), 13 deletions(-) diff --git a/lib/checkleakautovar.cpp b/lib/checkleakautovar.cpp index 6e0357a3f6c..274cfb17076 100644 --- a/lib/checkleakautovar.cpp +++ b/lib/checkleakautovar.cpp @@ -679,16 +679,14 @@ bool CheckLeakAutoVar::checkScope(const Token * const startToken, continue; functionCall(ftok, openingPar, varInfo, allocation, af); - const Token* const endPar = ftok->next()->link(); - if (af) - tok = endPar; + tok = ftok->next()->link(); // Handle scopes that might be noreturn - if (allocation.status == VarInfo::NOALLOC && Token::simpleMatch(endPar, ") ; }")) { + if (allocation.status == VarInfo::NOALLOC && Token::simpleMatch(tok, ") ; }")) { if (ftok->isKeyword()) continue; bool unknown = false; - if (mTokenizer->isScopeNoReturn(endPar->tokAt(2), &unknown)) { + if (mTokenizer->isScopeNoReturn(tok->tokAt(2), &unknown)) { if (!unknown) varInfo.clear(); else { diff --git a/test/testleakautovar.cpp b/test/testleakautovar.cpp index 81c3debd83d..73be514471c 100644 --- a/test/testleakautovar.cpp +++ b/test/testleakautovar.cpp @@ -940,14 +940,9 @@ class TestLeakAutoVar : public TestFixture { " free(p);\n" " strcpy(p, q);\n" "}\n", false, &s); - ASSERT_EQUALS("[test.c:3]: (error) Dereferencing 'p' after it is deallocated / released\n", - errout.str()); - - check("void f(const char* fn, const char* m) {\n" - " FILE* fp = fopen(fn, m);\n" - " fclose(fp);\n" - "}\n", false, &s); - ASSERT_EQUALS("", errout.str()); + TODO_ASSERT_EQUALS("[test.c:3]: (error) Dereferencing 'p' after it is deallocated / released\n", + "", + errout.str()); check("void f() {\n" " int *p = (int*)malloc(4);\n" From 38cb34c0bfa55fe4df9c904843be25129fe66a9d Mon Sep 17 00:00:00 2001 From: chrchr Date: Mon, 11 Dec 2023 17:39:47 +0100 Subject: [PATCH 04/10] Fix --- lib/checkleakautovar.cpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/lib/checkleakautovar.cpp b/lib/checkleakautovar.cpp index 274cfb17076..f684e7b7ccf 100644 --- a/lib/checkleakautovar.cpp +++ b/lib/checkleakautovar.cpp @@ -466,7 +466,9 @@ bool CheckLeakAutoVar::checkScope(const Token * const startToken, const Token * closingParenthesis = tok->linkAt(1); for (const Token *innerTok = tok->tokAt(2); innerTok && innerTok != closingParenthesis; innerTok = innerTok->next()) { // TODO: replace with checkTokenInsideExpression() - checkTokenInsideExpression(innerTok, varInfo); + const Token* const openingPar = isFunctionCall(innerTok); + if (!openingPar) + checkTokenInsideExpression(innerTok, varInfo); if (!isLocalVarNoAutoDealloc(innerTok, mTokenizer->isCPP())) continue; @@ -501,6 +503,15 @@ bool CheckLeakAutoVar::checkScope(const Token * const startToken, varAlloc.allocTok = innerTok->tokAt(2); } } + + // check for function call + if (openingPar) { + const Library::AllocFunc* allocFunc = mSettings->library.getDeallocFuncInfo(innerTok); + // innerTok is a function name + const VarInfo::AllocInfo allocation(0, VarInfo::NOALLOC); + functionCall(innerTok, openingPar, varInfo, allocation, allocFunc); + innerTok = openingPar->link(); + } } if (Token::simpleMatch(closingParenthesis, ") {")) { From b7b3c82b02f6dbb5bb4ba134590fb094f1086b46 Mon Sep 17 00:00:00 2001 From: chrchr-github Date: Mon, 11 Dec 2023 21:46:27 +0100 Subject: [PATCH 05/10] Try again --- lib/checkleakautovar.cpp | 5 +++-- test/testleakautovar.cpp | 5 ++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/checkleakautovar.cpp b/lib/checkleakautovar.cpp index f684e7b7ccf..0602bb1f541 100644 --- a/lib/checkleakautovar.cpp +++ b/lib/checkleakautovar.cpp @@ -933,8 +933,7 @@ void CheckLeakAutoVar::changeAllocStatus(VarInfo &varInfo, const VarInfo::AllocI void CheckLeakAutoVar::functionCall(const Token *tokName, const Token *tokOpeningPar, VarInfo &varInfo, const VarInfo::AllocInfo& allocation, const Library::AllocFunc* af) { // Ignore function call? - if (mSettings->library.isLeakIgnore(mSettings->library.getFunctionName(tokName))) - return; + const bool isLeakIgnore = mSettings->library.isLeakIgnore(mSettings->library.getFunctionName(tokName)); if (mSettings->library.getReallocFuncInfo(tokName)) return; @@ -993,6 +992,8 @@ void CheckLeakAutoVar::functionCall(const Token *tokName, const Token *tokOpenin varAlloc.allocTok = arg; } } + else if (isLeakIgnore) + checkTokenInsideExpression(arg, varInfo); else changeAllocStatus(varInfo, dealloc.type == 0 ? allocation : dealloc, tokName, arg); } diff --git a/test/testleakautovar.cpp b/test/testleakautovar.cpp index 73be514471c..adf60b1c4ab 100644 --- a/test/testleakautovar.cpp +++ b/test/testleakautovar.cpp @@ -940,9 +940,8 @@ class TestLeakAutoVar : public TestFixture { " free(p);\n" " strcpy(p, q);\n" "}\n", false, &s); - TODO_ASSERT_EQUALS("[test.c:3]: (error) Dereferencing 'p' after it is deallocated / released\n", - "", - errout.str()); + ASSERT_EQUALS("[test.c:3]: (error) Dereferencing 'p' after it is deallocated / released\n", + errout.str()); check("void f() {\n" " int *p = (int*)malloc(4);\n" From 5f9feb46b80520dbe1dd0c13d53ce4478fa79214 Mon Sep 17 00:00:00 2001 From: chrchr-github Date: Mon, 11 Dec 2023 21:59:32 +0100 Subject: [PATCH 06/10] Fix test --- test/testleakautovar.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/testleakautovar.cpp b/test/testleakautovar.cpp index adf60b1c4ab..1e4502b2c21 100644 --- a/test/testleakautovar.cpp +++ b/test/testleakautovar.cpp @@ -3024,7 +3024,7 @@ class TestLeakAutoVarStrcpy : public TestFixture { " free(p);\n" " strcpy(a, p);\n" "}"); - TODO_ASSERT_EQUALS("error (free,use)", "", errout.str()); + ASSERT_EQUALS("[test.cpp:3]: (error) Dereferencing 'p' after it is deallocated / released\n", errout.str()); check("void f(char *p) {\n" // #3041 - assigning pointer when it's used " free(p);\n" From a05410e73697388fba13c1ed6a2cfcf84338b8c7 Mon Sep 17 00:00:00 2001 From: chrchr-github Date: Mon, 11 Dec 2023 22:05:51 +0100 Subject: [PATCH 07/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 474f160245b..27f296de988 100644 --- a/test/cfg/posix.c +++ b/test/cfg/posix.c @@ -859,7 +859,7 @@ void memleak_scandir(void) which is allocated via malloc(3). If filter is NULL, all entries are selected.*/ - // TODO: cppcheck-suppress memleak + // cppcheck-suppress memleak } void no_memleak_scandir(void) From ad35c5473752d1d290f008d59676364633cbb690 Mon Sep 17 00:00:00 2001 From: chrchr-github Date: Mon, 11 Dec 2023 22:17:55 +0100 Subject: [PATCH 08/10] Move --- test/testleakautovar.cpp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/test/testleakautovar.cpp b/test/testleakautovar.cpp index 1e4502b2c21..d5cd3874daf 100644 --- a/test/testleakautovar.cpp +++ b/test/testleakautovar.cpp @@ -935,14 +935,6 @@ class TestLeakAutoVar : public TestFixture { ASSERT_EQUALS("[test.cpp:5]: (error) Dereferencing 's' after it is deallocated / released\n", errout.str()); - const Settings s = settingsBuilder().library("std.cfg").build(); - check("void f(char *p, const char *q) {\n" // #11665 - " free(p);\n" - " strcpy(p, q);\n" - "}\n", false, &s); - ASSERT_EQUALS("[test.c:3]: (error) Dereferencing 'p' after it is deallocated / released\n", - errout.str()); - check("void f() {\n" " int *p = (int*)malloc(4);\n" " free(p);\n" @@ -3026,6 +3018,13 @@ class TestLeakAutoVarStrcpy : public TestFixture { "}"); ASSERT_EQUALS("[test.cpp:3]: (error) Dereferencing 'p' after it is deallocated / released\n", errout.str()); + check("void f(char *p, const char *q) {\n" // #11665 + " free(p);\n" + " strcpy(p, q);\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:3]: (error) Dereferencing 'p' after it is deallocated / released\n", + errout.str()); + check("void f(char *p) {\n" // #3041 - assigning pointer when it's used " free(p);\n" " strcpy(a, p=b());\n" From e95caf643cf4deb3f3d3dc3accac61eec0587b73 Mon Sep 17 00:00:00 2001 From: chrchr-github Date: Wed, 13 Dec 2023 22:52:45 +0100 Subject: [PATCH 09/10] Add test for #8192 --- test/testcondition.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/test/testcondition.cpp b/test/testcondition.cpp index 17a28fbe892..8a57fd8f755 100644 --- a/test/testcondition.cpp +++ b/test/testcondition.cpp @@ -5194,6 +5194,16 @@ class TestCondition : public TestFixture { " for (int i = 0; i < N; a[i++] = false);\n" "}\n"); ASSERT_EQUALS("", errout.str()); + + check("void f() {\n" // #8192 + " for (int i = 0; i > 10; ++i) {}\n" + "}\n"); + TODO_ASSERT_EQUALS("[test.cpp:2]: (style) Condition 'i>10' is always false\n", "", errout.str()); + + check("void f() {\n" + " for (int i = 1000; i < 20; ++i) {}\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:2]: (style) Condition 'i<20' is always false\n", errout.str()); } void alwaysTrueTryCatch() From 3a32a6a61f1808a23359aa049ad6ca45e5e1a736 Mon Sep 17 00:00:00 2001 From: chrchr Date: Thu, 14 Dec 2023 15:26:34 +0100 Subject: [PATCH 10/10] Add test for #11540 --- test/testuninitvar.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/test/testuninitvar.cpp b/test/testuninitvar.cpp index 3b4c548c77d..94cd448ac16 100644 --- a/test/testuninitvar.cpp +++ b/test/testuninitvar.cpp @@ -6334,6 +6334,21 @@ class TestUninitVar : public TestFixture { " if (pwd == NULL) {}\n" "}"); ASSERT_EQUALS("[test.cpp:15] -> [test.cpp:17]: (warning) Uninitialized variable: pwd\n", errout.str()); + + valueFlowUninit("size_t Read(unsigned char* buffer, size_t len);\n" // #11540 + "void f() {\n" + " const int N = 100;\n" + " uint8_t data[N];\n" + " size_t data_size = 0;\n" + " for (int i = 0; i < 10; i++) {\n" + " if (!data_size)\n" + " data_size = Read(data, N);\n" + " if (!data_size)\n" + " return;\n" + " if (data[0] == 0x47) {}\n" + " }\n" + "}\n"); + ASSERT_EQUALS("", errout.str()); } void valueFlowUninitBreak() { // Do not show duplicate warnings about the same uninitialized value