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/2] 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/2] 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)