From c3b8295f53997854b6b65df5188908ebaf0258d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludvig=20Gunne=20Lindstr=C3=B6m?= Date: Mon, 21 Sep 2026 09:23:16 +0200 Subject: [PATCH 1/4] test --- test/testother.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/test/testother.cpp b/test/testother.cpp index f64745f80a4..804b973bf95 100644 --- a/test/testother.cpp +++ b/test/testother.cpp @@ -10070,6 +10070,22 @@ class TestOther : public TestFixture { ASSERT_EQUALS( "[test.cpp:2:9]: (style) Variable 'ptr' can be declared as pointer to const [constVariablePointer]\n", errout_str()); + + check("void f() {\n" + " char *p = new char[1];\n" + " ++p;\n" + " delete [] (p - 1);\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:2:11]: (style) Variable 'p' can be declared as pointer to const [constVariablePointer]\n", + errout_str()); + + check("void f() {\n" + " char *p = new char[1];\n" + " delete [] (p - 1);\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:2:11]: (style) Variable 'p' can be declared as pointer to const [constVariablePointer]\n" + "[test.cpp:3:5]: (error) Mismatching address is deleted. The address you get from new must be deleted without offset. [invalidFree]\n" + , errout_str()); } void checkRedundantCopy() { From 061ab7546ef7ab106d5a766fb26868d70f382237 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludvig=20Gunne=20Lindstr=C3=B6m?= Date: Mon, 21 Sep 2026 09:23:20 +0200 Subject: [PATCH 2/4] fix --- lib/checkother.cpp | 7 +++++++ lib/valueflow.cpp | 14 ++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/lib/checkother.cpp b/lib/checkother.cpp index b9ff731b0ce..e8d3b2554a3 100644 --- a/lib/checkother.cpp +++ b/lib/checkother.cpp @@ -2850,6 +2850,13 @@ void CheckOtherImpl::checkInvalidFree() const int varIndex = tok->strAt(1) == "(" ? 2 : tok->strAt(3) == "(" ? 4 : 1; + const Token *op = tok->tokAt(varIndex + 1); + if (std::any_of(op->values().cbegin(), + op->values().cend(), + [&](const ValueFlow::Value &value) { + return value.isSymbolicValue() && value.intvalue == 0; + })) + continue; const int var1 = tok->tokAt(varIndex)->varId(); const int var2 = tok->tokAt(varIndex + 2)->varId(); const auto alloc1 = utils::as_const(inconclusive).find(var1); diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index aa0b2c91c29..6607731e2f3 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -3737,6 +3737,20 @@ static void valueFlowSymbolicOperators(const SymbolDatabase& symboldatabase, con continue; if (Token::Match(tok, "<<|>>|/|-") && !astIsLHS(vartok)) continue; + if (Token::Match(tok, "+|-") && constant->intvalue != 0) { + std::unordered_set ids; + for (const auto &value : vartok->values()) { + if (!value.isSymbolicValue()) + continue; + if (!value.tokvalue) + continue; + if (!ids.insert(value.tokvalue->exprId()).second) + continue; + ValueFlow::Value newValue(value); + newValue.intvalue += tok->str() == "-" ? -constant->intvalue : constant->intvalue; + setTokenValue(tok, std::move(newValue), settings); + } + } if (Token::Match(tok, "<<|>>|^|+|-|%or%") && constant->intvalue != 0) continue; if (Token::Match(tok, "*|/") && constant->intvalue != 1) From f25e9350c89607e72c0af1ffb1775bb4060c6f0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludvig=20Gunne=20Lindstr=C3=B6m?= Date: Thu, 1 Oct 2026 12:44:40 +0200 Subject: [PATCH 3/4] new test --- test/testother.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/test/testother.cpp b/test/testother.cpp index 804b973bf95..5f0b105610b 100644 --- a/test/testother.cpp +++ b/test/testother.cpp @@ -10086,6 +10086,16 @@ class TestOther : public TestFixture { ASSERT_EQUALS("[test.cpp:2:11]: (style) Variable 'p' can be declared as pointer to const [constVariablePointer]\n" "[test.cpp:3:5]: (error) Mismatching address is deleted. The address you get from new must be deleted without offset. [invalidFree]\n" , errout_str()); + + check("void f() {\n" + " char *p = new char[2];\n" + " char *q = p - 1;\n" + " delete [] (p - 1);\n" + " (void)q;\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:2:11]: (style) Variable 'p' can be declared as pointer to const [constVariablePointer]\n" + "[test.cpp:4:5]: (error) Mismatching address is deleted. The address you get from new must be deleted without offset. [invalidFree]\n", + errout_str()); } void checkRedundantCopy() { From 7ae750bb643aa474c5a394023f6e8bdad97e0284 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludvig=20Gunne=20Lindstr=C3=B6m?= Date: Thu, 1 Oct 2026 12:44:46 +0200 Subject: [PATCH 4/4] update --- lib/checkother.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/checkother.cpp b/lib/checkother.cpp index e8d3b2554a3..3f05b679c03 100644 --- a/lib/checkother.cpp +++ b/lib/checkother.cpp @@ -2854,7 +2854,9 @@ void CheckOtherImpl::checkInvalidFree() if (std::any_of(op->values().cbegin(), op->values().cend(), [&](const ValueFlow::Value &value) { - return value.isSymbolicValue() && value.intvalue == 0; + if (!value.isSymbolicValue() || !value.isKnown() || value.intvalue != 0 || !value.tokvalue) + return false; + return value.tokvalue->str() == "new"; })) continue; const int var1 = tok->tokAt(varIndex)->varId();