From 1a7259ab14f7ddd690d1cd9684324fcb72e521df Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Fri, 13 Feb 2026 15:42:04 +0100 Subject: [PATCH 01/10] Update checkleakautovar.cpp --- lib/checkleakautovar.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/checkleakautovar.cpp b/lib/checkleakautovar.cpp index 0ff4bcd8931..bf49adda5b6 100644 --- a/lib/checkleakautovar.cpp +++ b/lib/checkleakautovar.cpp @@ -444,7 +444,7 @@ bool CheckLeakAutoVar::checkScope(const Token * const startToken, if (tok2->str() == ";") { break; } - if (tok2->varId()) { + if (tok2->varId() && !Token::Match(tok2->astParent(), "%comp%|!")) { varInfo.erase(tok2->varId()); } } From 90e662657ef86c5cb5af92feac649f9360364b78 Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Fri, 13 Feb 2026 16:03:54 +0100 Subject: [PATCH 02/10] Update checkleakautovar.cpp --- lib/checkleakautovar.cpp | 95 ++++++++++++++++++++++------------------ 1 file changed, 52 insertions(+), 43 deletions(-) diff --git a/lib/checkleakautovar.cpp b/lib/checkleakautovar.cpp index bf49adda5b6..0819a58b339 100644 --- a/lib/checkleakautovar.cpp +++ b/lib/checkleakautovar.cpp @@ -578,53 +578,62 @@ bool CheckLeakAutoVar::checkScope(const Token * const startToken, astOperand2AfterCommas = astOperand2AfterCommas->astOperand2(); // Recursively scan variable comparisons in condition - visitAstNodes(astOperand2AfterCommas, [&](const Token *tok3) { - if (!tok3) - return ChildrenToVisit::none; - if (tok3->str() == "&&" || tok3->str() == "||") { - // FIXME: handle && ! || better - return ChildrenToVisit::op1_and_op2; - } - if (tok3->str() == "(" && Token::Match(tok3->astOperand1(), "UNLIKELY|LIKELY")) { - return ChildrenToVisit::op2; - } - if (tok3->str() == "(" && tok3->previous()->isName()) { - const std::vector params = getArguments(tok3->previous()); - for (const Token *par : params) { - if (!par->isComparisonOp()) - continue; - const Token *vartok = nullptr; - if (isVarTokComparison(par, &vartok, alloc_success_conds) || - (isVarTokComparison(par, &vartok, alloc_failed_conds))) { - varInfo1.erase(vartok->varId()); - varInfo2.erase(vartok->varId()); + const Token* compToks[] = { + astOperand2AfterCommas, + astOperand2AfterCommas->hasKnownValue(ValueFlow::Value::ValueType::SYMBOLIC) ? astOperand2AfterCommas->getKnownValue(ValueFlow::Value::ValueType::SYMBOLIC)->tokvalue : nullptr + }; + for (auto compTok : compToks) { + if (!compTok) + continue; + visitAstNodes(compTok, [&](const Token* tok3) { + if (!tok3) + return ChildrenToVisit::none; + if (tok3->str() == "&&" || tok3->str() == "||") { + // FIXME: handle && ! || better + return ChildrenToVisit::op1_and_op2; + } + if (tok3->str() == "(" && Token::Match(tok3->astOperand1(), "UNLIKELY|LIKELY")) { + return ChildrenToVisit::op2; + } + if (tok3->str() == "(" && tok3->previous()->isName()) { + const std::vector params = getArguments(tok3->previous()); + for (const Token* par : params) { + if (!par->isComparisonOp()) + continue; + const Token* vartok = nullptr; + if (isVarTokComparison(par, &vartok, alloc_success_conds) || + (isVarTokComparison(par, &vartok, alloc_failed_conds))) { + varInfo1.erase(vartok->varId()); + varInfo2.erase(vartok->varId()); + } } + return ChildrenToVisit::none; } - return ChildrenToVisit::none; - } - const Token *vartok = nullptr; - if (isVarTokComparison(tok3, &vartok, alloc_success_conds)) { - varInfo2.reallocToAlloc(vartok->varId()); - varInfo2.erase(vartok->varId()); - if (astIsVariableComparison(tok3, "!=", "0", &vartok) && - (notzero.find(vartok->varId()) != notzero.end())) - varInfo2.clear(); - - if (std::any_of(varInfo1.alloctype.begin(), varInfo1.alloctype.end(), [&](const std::pair& info) { - if (info.second.status != VarInfo::ALLOC) - return false; - const Token* ret = getReturnValueFromOutparamAlloc(info.second.allocTok, *mSettings); - return ret && vartok && ret->varId() && ret->varId() == vartok->varId(); - })) { - varInfo1.clear(); + const Token* vartok = nullptr; + if (isVarTokComparison(tok3, &vartok, alloc_success_conds)) { + varInfo2.reallocToAlloc(vartok->varId()); + varInfo2.erase(vartok->varId()); + if (astIsVariableComparison(tok3, "!=", "0", &vartok) && + (notzero.find(vartok->varId()) != notzero.end())) + varInfo2.clear(); + + if (std::any_of(varInfo1.alloctype.begin(), varInfo1.alloctype.end(), [&](const std::pair& info) { + if (info.second.status != VarInfo::ALLOC) + return false; + const Token* ret = getReturnValueFromOutparamAlloc(info.second.allocTok, *mSettings); + return ret && vartok && ret->varId() && ret->varId() == vartok->varId(); + })) { + varInfo1.clear(); + } } - } else if (isVarTokComparison(tok3, &vartok, alloc_failed_conds)) { - varInfo1.reallocToAlloc(vartok->varId()); - varInfo1.erase(vartok->varId()); - } - return ChildrenToVisit::none; - }); + else if (isVarTokComparison(tok3, &vartok, alloc_failed_conds)) { + varInfo1.reallocToAlloc(vartok->varId()); + varInfo1.erase(vartok->varId()); + } + return ChildrenToVisit::none; + }); + } if (!skipIfBlock && !checkScope(closingParenthesis->next(), varInfo1, notzero, recursiveCount)) { varInfo.clear(); From 32a1c68286baa681fc2caa9dbab1b34fcdf13ed5 Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Fri, 13 Feb 2026 16:04:49 +0100 Subject: [PATCH 03/10] Update testleakautovar.cpp --- test/testleakautovar.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/testleakautovar.cpp b/test/testleakautovar.cpp index 7aa64c1cd3c..d2448c5ebf6 100644 --- a/test/testleakautovar.cpp +++ b/test/testleakautovar.cpp @@ -641,6 +641,14 @@ class TestLeakAutoVar : public TestFixture { " x = p != nullptr ? p : nullptr;\n" "}", dinit(CheckOptions, $.cpp = true)); ASSERT_EQUALS("", errout_str()); + + check("void f(const char* n) {\n" // #12724 + " FILE* fp = fopen(n, \"r\");\n" + "bool b = (fp == NULL);\n" + "if (b)\n" + " return;\n" + "}\n", dinit(CheckOptions, $.cpp = true)); + ASSERT_EQUALS("[test.cpp:6:1]: (error) Resource leak: fp [resourceLeak]\n", errout_str()); } void memcpy1() { // #11542 From 8ec5842ca3bd3de557e47db788e037d3b37491ab Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Fri, 13 Feb 2026 16:16:48 +0100 Subject: [PATCH 04/10] Update checkleakautovar.cpp --- lib/checkleakautovar.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/checkleakautovar.cpp b/lib/checkleakautovar.cpp index 0819a58b339..3bfa49c19d0 100644 --- a/lib/checkleakautovar.cpp +++ b/lib/checkleakautovar.cpp @@ -623,7 +623,7 @@ bool CheckLeakAutoVar::checkScope(const Token * const startToken, return false; const Token* ret = getReturnValueFromOutparamAlloc(info.second.allocTok, *mSettings); return ret && vartok && ret->varId() && ret->varId() == vartok->varId(); - })) { + })) { varInfo1.clear(); } } From 1352ad462d804bbfaee9d87c331d08a4b56c46b9 Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Fri, 13 Feb 2026 18:34:38 +0100 Subject: [PATCH 05/10] Update checkleakautovar.cpp --- lib/checkleakautovar.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/checkleakautovar.cpp b/lib/checkleakautovar.cpp index 3bfa49c19d0..0cc7e39ebea 100644 --- a/lib/checkleakautovar.cpp +++ b/lib/checkleakautovar.cpp @@ -582,7 +582,7 @@ bool CheckLeakAutoVar::checkScope(const Token * const startToken, astOperand2AfterCommas, astOperand2AfterCommas->hasKnownValue(ValueFlow::Value::ValueType::SYMBOLIC) ? astOperand2AfterCommas->getKnownValue(ValueFlow::Value::ValueType::SYMBOLIC)->tokvalue : nullptr }; - for (auto compTok : compToks) { + for (const Token* compTok : compToks) { if (!compTok) continue; visitAstNodes(compTok, [&](const Token* tok3) { From c8a70f155ad64cdd12702d3b12e78452c859fef4 Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Fri, 13 Feb 2026 18:38:14 +0100 Subject: [PATCH 06/10] Update checkleakautovar.cpp --- lib/checkleakautovar.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/checkleakautovar.cpp b/lib/checkleakautovar.cpp index 0cc7e39ebea..8e9f645cdb9 100644 --- a/lib/checkleakautovar.cpp +++ b/lib/checkleakautovar.cpp @@ -632,7 +632,7 @@ bool CheckLeakAutoVar::checkScope(const Token * const startToken, varInfo1.erase(vartok->varId()); } return ChildrenToVisit::none; - }); + }); } if (!skipIfBlock && !checkScope(closingParenthesis->next(), varInfo1, notzero, recursiveCount)) { From 014ec2f4d0a0b37f8cd2c40d89c52e6e5d6083f6 Mon Sep 17 00:00:00 2001 From: chrchr-github Date: Fri, 13 Feb 2026 22:27:06 +0100 Subject: [PATCH 07/10] Check condition stored in variable --- lib/checkleakautovar.cpp | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/lib/checkleakautovar.cpp b/lib/checkleakautovar.cpp index 8e9f645cdb9..9ff98974a2d 100644 --- a/lib/checkleakautovar.cpp +++ b/lib/checkleakautovar.cpp @@ -295,6 +295,18 @@ static const Token* getReturnValueFromOutparamAlloc(const Token* alloc, const Se return nullptr; } +static std::vector getComparisonTokens(const Token* tok) +{ + std::vector result{ tok }; + if (tok->hasKnownValue(ValueFlow::Value::ValueType::SYMBOLIC)) + result.push_back(tok->getKnownValue(ValueFlow::Value::ValueType::SYMBOLIC)->tokvalue); + for (const Token* op : { tok->astOperand1(), tok->astOperand2() }) { + if (op && op->hasKnownValue(ValueFlow::Value::ValueType::SYMBOLIC)) + result.push_back(op->getKnownValue(ValueFlow::Value::ValueType::SYMBOLIC)->tokvalue); + } + return result; +} + bool CheckLeakAutoVar::checkScope(const Token * const startToken, VarInfo &varInfo, std::set notzero, @@ -578,13 +590,8 @@ bool CheckLeakAutoVar::checkScope(const Token * const startToken, astOperand2AfterCommas = astOperand2AfterCommas->astOperand2(); // Recursively scan variable comparisons in condition - const Token* compToks[] = { - astOperand2AfterCommas, - astOperand2AfterCommas->hasKnownValue(ValueFlow::Value::ValueType::SYMBOLIC) ? astOperand2AfterCommas->getKnownValue(ValueFlow::Value::ValueType::SYMBOLIC)->tokvalue : nullptr - }; + const std::vector compToks = getComparisonTokens(astOperand2AfterCommas); for (const Token* compTok : compToks) { - if (!compTok) - continue; visitAstNodes(compTok, [&](const Token* tok3) { if (!tok3) return ChildrenToVisit::none; From 682f9d89cca7da9d1a36571260653a482d0d26b1 Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Sat, 21 Feb 2026 22:36:53 +0100 Subject: [PATCH 08/10] Update lib/checkleakautovar.cpp MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Daniel Marjamäki --- lib/checkleakautovar.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/checkleakautovar.cpp b/lib/checkleakautovar.cpp index 9ff98974a2d..b90b69de9a5 100644 --- a/lib/checkleakautovar.cpp +++ b/lib/checkleakautovar.cpp @@ -590,8 +590,7 @@ bool CheckLeakAutoVar::checkScope(const Token * const startToken, astOperand2AfterCommas = astOperand2AfterCommas->astOperand2(); // Recursively scan variable comparisons in condition - const std::vector compToks = getComparisonTokens(astOperand2AfterCommas); - for (const Token* compTok : compToks) { + for (const Token* compTok : getComparisonTokens(astOperand2AfterCommas) { visitAstNodes(compTok, [&](const Token* tok3) { if (!tok3) return ChildrenToVisit::none; From f60c18c0cebf18b56a5a07f9183a6eb4626b57b1 Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Mon, 23 Feb 2026 19:24:58 +0100 Subject: [PATCH 09/10] Update checkleakautovar.cpp --- lib/checkleakautovar.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/checkleakautovar.cpp b/lib/checkleakautovar.cpp index b90b69de9a5..148bd43c689 100644 --- a/lib/checkleakautovar.cpp +++ b/lib/checkleakautovar.cpp @@ -590,7 +590,7 @@ bool CheckLeakAutoVar::checkScope(const Token * const startToken, astOperand2AfterCommas = astOperand2AfterCommas->astOperand2(); // Recursively scan variable comparisons in condition - for (const Token* compTok : getComparisonTokens(astOperand2AfterCommas) { + for (const Token* compTok : getComparisonTokens(astOperand2AfterCommas)) { visitAstNodes(compTok, [&](const Token* tok3) { if (!tok3) return ChildrenToVisit::none; From 508035341446b52f5f9083aa3c2e97b8bfdad528 Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Wed, 25 Feb 2026 08:02:58 +0100 Subject: [PATCH 10/10] Update testleakautovar.cpp --- test/testleakautovar.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/testleakautovar.cpp b/test/testleakautovar.cpp index d2448c5ebf6..d23a655b492 100644 --- a/test/testleakautovar.cpp +++ b/test/testleakautovar.cpp @@ -644,9 +644,9 @@ class TestLeakAutoVar : public TestFixture { check("void f(const char* n) {\n" // #12724 " FILE* fp = fopen(n, \"r\");\n" - "bool b = (fp == NULL);\n" - "if (b)\n" - " return;\n" + " bool b = (fp == NULL);\n" + " if (b)\n" + " return;\n" "}\n", dinit(CheckOptions, $.cpp = true)); ASSERT_EQUALS("[test.cpp:6:1]: (error) Resource leak: fp [resourceLeak]\n", errout_str()); }