From 8207a0066d3279698863f6ffe1e1fdb378587103 Mon Sep 17 00:00:00 2001 From: chrchr-github Date: Tue, 23 Jun 2026 22:16:50 +0200 Subject: [PATCH 1/2] Refs #14859: Fix sizeof calculation for std::array --- lib/symboldatabase.cpp | 14 +++++++++----- lib/vf_common.cpp | 10 ++++++++-- test/testvalueflow.cpp | 14 ++++++++++++++ 3 files changed, 31 insertions(+), 7 deletions(-) diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index ba5c31d1f47..866b856a72d 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -8478,7 +8478,7 @@ namespace { } template -static Result accumulateStructMembers(const Scope* scope, F f, ValueType::Accuracy accuracy) +static Result accumulateStructMembers(const Scope* scope, F f, ValueType::Accuracy accuracy, const Settings& settings) { size_t total = 0; std::set anonScopes; @@ -8497,6 +8497,10 @@ static Result accumulateStructMembers(const Scope* scope, F f, ValueType::Accura if (ret.second) total = f(total, *vt, dim, bits); } + else if (vt->container && vt->container->startPattern == "std :: array <") { + const ValueType vtElement = ValueType::parseDecl(vt->containerTypeToken, settings); + total = f(total, vtElement, dim, bits); + } else total = f(total, *vt, dim, bits); } @@ -8536,12 +8540,12 @@ static size_t getAlignOf(const ValueType& vt, const Settings& settings, ValueTyp size_t a = getAlignOf(vt2, settings, accuracy, ValueType::SizeOf::Pointer, ++maxRecursion); return std::max(max, a); }; - Result result = accumulateStructMembers(vt.typeScope, accHelper, accuracy); + Result result = accumulateStructMembers(vt.typeScope, accHelper, accuracy, settings); size_t total = result.total; if (const Type* dt = vt.typeScope->definedType) { total = std::accumulate(dt->derivedFrom.begin(), dt->derivedFrom.end(), total, [&](size_t v, const Type::BaseInfo& bi) { if (bi.type && bi.type->classScope) - v += accumulateStructMembers(bi.type->classScope, accHelper, accuracy).total; + v += accumulateStructMembers(bi.type->classScope, accHelper, accuracy, settings).total; return v; }); } @@ -8629,14 +8633,14 @@ size_t ValueType::getSizeOf( const Settings& settings, Accuracy accuracy, SizeOf } return typeScope->type == ScopeType::eUnion ? std::max(total, n) : total + padding + n; }; - Result result = accumulateStructMembers(typeScope, accHelper, accuracy); + Result result = accumulateStructMembers(typeScope, accHelper, accuracy, settings); size_t total = result.total; if (currentBitCount > 0) total += currentBitfieldAlloc; if (const ::Type* dt = typeScope->definedType) { total = std::accumulate(dt->derivedFrom.begin(), dt->derivedFrom.end(), total, [&](size_t v, const ::Type::BaseInfo& bi) { if (bi.type && bi.type->classScope) - v += accumulateStructMembers(bi.type->classScope, accHelper, accuracy).total; + v += accumulateStructMembers(bi.type->classScope, accHelper, accuracy, settings).total; return v; }); } diff --git a/lib/vf_common.cpp b/lib/vf_common.cpp index 56f928bcbd8..b7d218cbab3 100644 --- a/lib/vf_common.cpp +++ b/lib/vf_common.cpp @@ -165,7 +165,8 @@ namespace ValueFlow if (obj && !obj->isLiteral() && obj->valueType() && (obj->valueType()->pointer == 0 || // <- TODO this is a bailout, abort when there are array->pointer conversions (obj->variable() && !obj->variable()->isArray())) && - !obj->valueType()->isEnum()) { // <- TODO this is a bailout, handle enum with non-int types + !obj->valueType()->isEnum() && + !(obj->valueType()->container && obj->valueType()->container->startPattern == "std :: array <")) { // <- TODO this is a bailout, handle enum with non-int types const auto ptrPointee = obj->valueType()->pointer > 0 ? ValueType::SizeOf::Pointer : ValueType::SizeOf::Pointee; const size_t sz = obj->valueType()->getSizeOf(settings, ValueType::Accuracy::ExactOrZero, ptrPointee); if (sz) { @@ -246,7 +247,12 @@ namespace ValueFlow if (var->type()->classScope && var->type()->classScope->enumType) size = getSizeOfType(var->type()->classScope->enumType, settings); } else if (var->valueType()) { - size = var->valueType()->getSizeOf(settings, ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointer); + if (var->valueType()->container && var->valueType()->container->startPattern == "std :: array <") { + const ValueType vtElement = ValueType::parseDecl(var->valueType()->containerTypeToken, settings); + size = vtElement.getSizeOf(settings, ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointer); + } + else + size = var->valueType()->getSizeOf(settings, ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointer); } else if (!var->type()) { size = getSizeOfType(var->typeStartToken(), settings); } diff --git a/test/testvalueflow.cpp b/test/testvalueflow.cpp index 8305a63bc56..b338701765e 100644 --- a/test/testvalueflow.cpp +++ b/test/testvalueflow.cpp @@ -1812,6 +1812,20 @@ class TestValueFlow : public TestFixture { ASSERT_EQUALS(1U, values.size()); ASSERT_EQUALS(2 * settings.platform.sizeof_pointer, values.back().intvalue); ASSERT_EQUALS_ENUM(ValueFlow::Value::ValueKind::Known, values.back().valueKind); + + code = "struct S { std::array a; };\n" + "x = sizeof(S);\n"; + values = tokenValues(code, "( S"); + ASSERT_EQUALS(1U, values.size()); + ASSERT_EQUALS(3 * settings.platform.sizeof_int, values.back().intvalue); + ASSERT_EQUALS_ENUM(ValueFlow::Value::ValueKind::Known, values.back().valueKind); + + code = "std::array a;\n" + "x = sizeof(a);\n"; + values = tokenValues(code, "( a"); + ASSERT_EQUALS(1U, values.size()); + ASSERT_EQUALS(3 * settings.platform.sizeof_int, values.back().intvalue); + ASSERT_EQUALS_ENUM(ValueFlow::Value::ValueKind::Known, values.back().valueKind); } void valueFlowComma() From 1232c52e7fcfe7c55a37d5eaca4e137f1fc38501 Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Wed, 24 Jun 2026 10:11:18 +0200 Subject: [PATCH 2/2] Move comment [skip ci] --- lib/vf_common.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/vf_common.cpp b/lib/vf_common.cpp index b7d218cbab3..b4bd756d05e 100644 --- a/lib/vf_common.cpp +++ b/lib/vf_common.cpp @@ -165,8 +165,8 @@ namespace ValueFlow if (obj && !obj->isLiteral() && obj->valueType() && (obj->valueType()->pointer == 0 || // <- TODO this is a bailout, abort when there are array->pointer conversions (obj->variable() && !obj->variable()->isArray())) && - !obj->valueType()->isEnum() && - !(obj->valueType()->container && obj->valueType()->container->startPattern == "std :: array <")) { // <- TODO this is a bailout, handle enum with non-int types + !obj->valueType()->isEnum() && // <- TODO this is a bailout, handle enum with non-int types + !(obj->valueType()->container && obj->valueType()->container->startPattern == "std :: array <")) { const auto ptrPointee = obj->valueType()->pointer > 0 ? ValueType::SizeOf::Pointer : ValueType::SizeOf::Pointee; const size_t sz = obj->valueType()->getSizeOf(settings, ValueType::Accuracy::ExactOrZero, ptrPointee); if (sz) {