From 2ae134e0830a7801f202ebcaf18b33539fc2ad13 Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Fri, 24 Jul 2026 13:41:51 +0200 Subject: [PATCH 1/6] Update astutils.cpp --- lib/astutils.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/astutils.cpp b/lib/astutils.cpp index ea54232b551..2a231dccfd5 100644 --- a/lib/astutils.cpp +++ b/lib/astutils.cpp @@ -2778,7 +2778,7 @@ bool isVariableChanged(const Token *tok, int indirect, const Settings &settings, if (ftok->str() == "(" && Token::simpleMatch(ftok->astOperand1(), "[")) // operator() on array element, bail out return true; const Token * ptok = tok2; - while (Token::Match(ptok->astParent(), ".|::|[")) + while (Token::Match(ptok->astParent(), ".|::")) ptok = ptok->astParent(); int pindirect = indirect; if (indirect == 0 && astIsLHS(tok2) && Token::Match(ptok, ". %var%") && astIsPointer(ptok->next())) From 890e60573f5b9a4092c34699920b971e45126afa Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Fri, 24 Jul 2026 13:44:05 +0200 Subject: [PATCH 2/6] Update testvalueflow.cpp --- test/testvalueflow.cpp | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/test/testvalueflow.cpp b/test/testvalueflow.cpp index abeb603b660..45c7f884715 100644 --- a/test/testvalueflow.cpp +++ b/test/testvalueflow.cpp @@ -5112,6 +5112,27 @@ class TestValueFlow : public TestFixture { ++it; ASSERT_EQUALS(0, it->intvalue); ASSERT(it->isPossible()); + + code = "void g(int*);\n" + "void f(int* a) {\n" + " for (int i = 0; i < 5; ++i) {\n" + " g(&a[i]);\n" + " }\n" + "}\n"; + values = tokenValues(code, "i ]"); + ASSERT_EQUALS(4, values.size()); + it = values.begin(); + ASSERT_EQUALS(0, it->intvalue); + ASSERT(it->isPossible()); + ++it; + ASSERT_EQUALS(-1, it->intvalue); + ASSERT(it->isImpossible()); + ++it; + ASSERT_EQUALS(4, it->intvalue); + ASSERT(it->isPossible()); + ++it; + ASSERT_EQUALS(5, it->intvalue); + ASSERT(it->isImpossible()); } void valueFlowSubFunction() { From b67bbb7d45918eda6de43b7c0598111bde560212 Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Fri, 24 Jul 2026 13:54:51 +0200 Subject: [PATCH 3/6] Update testbufferoverrun.cpp --- test/testbufferoverrun.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/test/testbufferoverrun.cpp b/test/testbufferoverrun.cpp index b44fd742ab1..aa94b45d8f6 100644 --- a/test/testbufferoverrun.cpp +++ b/test/testbufferoverrun.cpp @@ -3537,7 +3537,7 @@ class TestBufferOverrun : public TestFixture { "}\n"); TODO_ASSERT_EQUALS("[test.cpp:3:12]: (error) Buffer is accessed out of bounds: &a[5] [bufferAccessOutOfBounds]\n" "[test.cpp:7:12]: (error) Buffer is accessed out of bounds: &a[0][0] [bufferAccessOutOfBounds]\n", - "", + "[test.cpp:3:12]: (error) Buffer is accessed out of bounds: &a[5] [bufferAccessOutOfBounds]\n", errout_str()); check("void f() {\n" // #14866 @@ -3552,11 +3552,12 @@ class TestBufferOverrun : public TestFixture { "}\n"); ASSERT_EQUALS("[test.cpp:3:17]: (error) Buffer is accessed out of bounds: &buf[0] [bufferAccessOutOfBounds]\n", errout_str()); - check("void f(FILE *fp) {\n" // #14929 - " std::string s;\n" - " fwrite(&s, 1, 1, fp);\n" + check("void f() {\n" + " int a[5];\n" + " for (int i = 0; i < 5; ++i)\n" + " memset(&a[i], 0, sizeof(a));\n" "}\n"); - ASSERT_EQUALS("", errout_str()); // don't crash + ASSERT_EQUALS("[test.cpp:4:16]: (error) Buffer is accessed out of bounds: &a[i] [bufferAccessOutOfBounds]\n", errout_str()); } void buffer_overrun_errorpath() { @@ -3814,7 +3815,7 @@ class TestBufferOverrun : public TestFixture { " int i[10];\n" " memset(&i[1], 0, 1000);\n" "}"); - TODO_ASSERT_EQUALS("[test.cpp:3:10]: (error) Buffer is accessed out of bounds: &i[1] [bufferAccessOutOfBounds]\n", "", errout_str()); + ASSERT_EQUALS("[test.cpp:3:10]: (error) Buffer is accessed out of bounds: &i[1] [bufferAccessOutOfBounds]\n", errout_str()); check("struct S { int x; };\n" // #8616 "void f() {\n" From 7784aac7dad706216beb14d1399437d3838dd2a3 Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Fri, 24 Jul 2026 13:56:35 +0200 Subject: [PATCH 4/6] Update checkbufferoverrun.cpp --- lib/checkbufferoverrun.cpp | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/lib/checkbufferoverrun.cpp b/lib/checkbufferoverrun.cpp index 246d428802e..0e4205306cf 100644 --- a/lib/checkbufferoverrun.cpp +++ b/lib/checkbufferoverrun.cpp @@ -560,12 +560,18 @@ ValueFlow::Value CheckBufferOverrunImpl::getBufferSize(const Token *bufTok, cons if (!bufTok->valueType()) return ValueFlow::Value(-1); + MathLib::bigint index = 0; if (bufTok->isUnaryOp("&")) { bufTok = bufTok->astOperand1(); if (Token::simpleMatch(bufTok, "[")) { - const Token* index = bufTok->astOperand2(); - if (!(index && index->hasKnownIntValue() && index->getKnownIntValue() == 0)) - return ValueFlow::Value(-1); + if (const Token* indexTok = bufTok->astOperand2()) { + if (indexTok->hasKnownIntValue()) + index = indexTok->getKnownIntValue(); + else if (const ValueFlow::Value* maxValue = indexTok->getMaxValue(false)) + index = maxValue->intvalue; + else + return ValueFlow::Value(-1); + } bufTok = bufTok->astOperand1(); } } @@ -575,7 +581,7 @@ ValueFlow::Value CheckBufferOverrunImpl::getBufferSize(const Token *bufTok, cons if (const ValueFlow::Value *value = getBufferSizeValue(bufTok)) { if (value->isBufferSizeValue()) return *value; - if (value->isContainerSizeValue() && bufTok->valueType() && bufTok->valueType()->containerTypeToken) { + if (value->isContainerSizeValue() && bufTok->valueType() && bufTok->valueType()->container) { const ValueType vtElement = ValueType::parseDecl(bufTok->valueType()->containerTypeToken, settings); const size_t elementSize = vtElement.getSizeOf(settings, ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointer); if (elementSize > 0) { @@ -600,10 +606,10 @@ ValueFlow::Value CheckBufferOverrunImpl::getBufferSize(const Token *bufTok, cons v.valueType = ValueFlow::Value::ValueType::BUFFER_SIZE; if (var->isPointerArray()) - v.intvalue = dim * mSettings.platform.sizeof_pointer; + v.intvalue = (dim - index) * mSettings.platform.sizeof_pointer; else { const size_t typeSize = bufTok->valueType()->getSizeOf(mSettings, ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointee); - v.intvalue = dim * typeSize; + v.intvalue = (dim - index) * typeSize; } return v; From 2d836e0a3725146c6c35641c1e55bfd045524ed0 Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Fri, 24 Jul 2026 14:44:32 +0200 Subject: [PATCH 5/6] Update testbufferoverrun.cpp --- test/testbufferoverrun.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/test/testbufferoverrun.cpp b/test/testbufferoverrun.cpp index aa94b45d8f6..37ab7083902 100644 --- a/test/testbufferoverrun.cpp +++ b/test/testbufferoverrun.cpp @@ -3552,7 +3552,13 @@ class TestBufferOverrun : public TestFixture { "}\n"); ASSERT_EQUALS("[test.cpp:3:17]: (error) Buffer is accessed out of bounds: &buf[0] [bufferAccessOutOfBounds]\n", errout_str()); - check("void f() {\n" + check("void f(FILE *fp) {\n" // #14929 + " std::string s;\n" + " fwrite(&s, 1, 1, fp);\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); // don't crash + + check("void f() {\n" // #14935 " int a[5];\n" " for (int i = 0; i < 5; ++i)\n" " memset(&a[i], 0, sizeof(a));\n" From 129e4b76d019aefc1c0ffab66d6e959b4d340df8 Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Fri, 24 Jul 2026 14:49:34 +0200 Subject: [PATCH 6/6] Update checkbufferoverrun.cpp --- lib/checkbufferoverrun.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/checkbufferoverrun.cpp b/lib/checkbufferoverrun.cpp index 0e4205306cf..46d8e1c7c6c 100644 --- a/lib/checkbufferoverrun.cpp +++ b/lib/checkbufferoverrun.cpp @@ -581,7 +581,7 @@ ValueFlow::Value CheckBufferOverrunImpl::getBufferSize(const Token *bufTok, cons if (const ValueFlow::Value *value = getBufferSizeValue(bufTok)) { if (value->isBufferSizeValue()) return *value; - if (value->isContainerSizeValue() && bufTok->valueType() && bufTok->valueType()->container) { + if (value->isContainerSizeValue() && bufTok->valueType() && bufTok->valueType()->containerTypeToken) { const ValueType vtElement = ValueType::parseDecl(bufTok->valueType()->containerTypeToken, settings); const size_t elementSize = vtElement.getSizeOf(settings, ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointer); if (elementSize > 0) {