From de86e716bf3ad917973ccb65e7678b5044fdec7a Mon Sep 17 00:00:00 2001 From: chrchr-github Date: Mon, 1 Dec 2025 20:23:13 +0100 Subject: [PATCH 01/17] Fix #14305 Wrong buffer sizes computed by valueFlowDynamicBufferSize() --- lib/valueflow.cpp | 7 +++++-- test/testvalueflow.cpp | 26 ++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index 8eb5735c986..78a7a7c357a 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -7078,8 +7078,11 @@ static void valueFlowDynamicBufferSize(const TokenList& tokenlist, const SymbolD if (!typeTok || !typeTok->varId()) typeTok = newTok->astParent()->previous(); // hack for "int** z = ..." if (typeTok && typeTok->valueType()) { - const MathLib::bigint typeSize = typeTok->valueType()->typeSize(settings.platform, typeTok->valueType()->pointer > 1); - if (typeSize >= 0) + ValueType vt = *typeTok->valueType(); + if (vt.pointer > 0) + --vt.pointer; + const MathLib::bigint typeSize = ValueFlow::getSizeOf(vt, settings, ValueFlow::Accuracy::ExactOrZero); + if (typeSize > 0 || numElem == 0) sizeValue = numElem * typeSize; } } diff --git a/test/testvalueflow.cpp b/test/testvalueflow.cpp index 71578810017..b910ca95cde 100644 --- a/test/testvalueflow.cpp +++ b/test/testvalueflow.cpp @@ -7457,6 +7457,32 @@ class TestValueFlow : public TestFixture { "}"; ASSERT_EQUALS(true, testValueOfX(code, 4U, 100, ValueFlow::Value::ValueType::BUFFER_SIZE)); + code = "struct A {};\n" // #14305 + "void* f() {\n" + " A* x = new A();\n" + " return x;\n" + "}"; + ASSERT_EQUALS(true, testValueOfX(code, 4U, 1, ValueFlow::Value::ValueType::BUFFER_SIZE)); + + code = "struct A {};\n" + "void* f() {\n" + " void* x = new A;\n" + " return x;\n" + "}"; + { + auto values = tokenValues(code, "x ; }"); + ASSERT_EQUALS(1, values.size()); + ASSERT(values.front().isSymbolicValue()); + // TODO: add BUFFER_SIZE value = 1 + } + + code = "struct B { int32_t i; };\n" + "void* f() {\n" + " B* x = new B();\n" + " return x;\n" + "}"; + ASSERT_EQUALS(true, testValueOfX(code, 4U, 4, ValueFlow::Value::ValueType::BUFFER_SIZE)); + settings = settingsOld; } From 49ae1cbbe62eafa76eef1eb4761e8c8feb619312 Mon Sep 17 00:00:00 2001 From: chrchr-github Date: Mon, 1 Dec 2025 20:25:45 +0100 Subject: [PATCH 02/17] Fornat --- test/testvalueflow.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test/testvalueflow.cpp b/test/testvalueflow.cpp index b910ca95cde..1884dea3d4f 100644 --- a/test/testvalueflow.cpp +++ b/test/testvalueflow.cpp @@ -7469,12 +7469,12 @@ class TestValueFlow : public TestFixture { " void* x = new A;\n" " return x;\n" "}"; - { - auto values = tokenValues(code, "x ; }"); - ASSERT_EQUALS(1, values.size()); - ASSERT(values.front().isSymbolicValue()); - // TODO: add BUFFER_SIZE value = 1 - } + { + auto values = tokenValues(code, "x ; }"); + ASSERT_EQUALS(1, values.size()); + ASSERT(values.front().isSymbolicValue()); + // TODO: add BUFFER_SIZE value = 1 + } code = "struct B { int32_t i; };\n" "void* f() {\n" From 602e2a7b2ddf65b220592ae6a32b6ae7f3930e07 Mon Sep 17 00:00:00 2001 From: chrchr-github Date: Mon, 8 Dec 2025 19:44:29 +0100 Subject: [PATCH 03/17] Unify typeSize() and getSizeOf() --- lib/checkbufferoverrun.cpp | 11 ++- lib/checkclass.cpp | 4 +- lib/checkleakautovar.cpp | 10 +- lib/checkmemoryleak.cpp | 4 +- lib/checkother.cpp | 20 ++-- lib/checktype.cpp | 8 +- lib/clangimport.cpp | 4 +- lib/ctu.cpp | 4 +- lib/symboldatabase.cpp | 190 +++++++++++++++++++++++++++++++++---- lib/symboldatabase.h | 10 +- lib/token.cpp | 2 +- lib/valueflow.cpp | 183 +---------------------------------- lib/valueflow.h | 10 -- lib/vf_analyzers.cpp | 4 +- lib/vf_common.cpp | 16 ++-- lib/vf_settokenvalue.cpp | 18 ++-- test/testmemleak.cpp | 2 +- 17 files changed, 231 insertions(+), 269 deletions(-) diff --git a/lib/checkbufferoverrun.cpp b/lib/checkbufferoverrun.cpp index 337f2b1de3f..9f9a00893db 100644 --- a/lib/checkbufferoverrun.cpp +++ b/lib/checkbufferoverrun.cpp @@ -229,7 +229,8 @@ static bool getDimensionsEtc(const Token * const arrayToken, const Settings &set Dimension dim; dim.known = value->isKnown(); dim.tok = nullptr; - const MathLib::bigint typeSize = array->valueType()->typeSize(settings.platform, array->valueType()->pointer > 1); + const auto sizeOf = array->valueType()->pointer > 1 ? ValueType::SizeOf::Pointer : ValueType::SizeOf::Pointee; + const MathLib::bigint typeSize = array->valueType()->getSizeOf(settings, ValueType::Accuracy::ExactOrZero, sizeOf); if (typeSize == 0) return false; dim.num = value->intvalue / typeSize; @@ -585,7 +586,7 @@ ValueFlow::Value CheckBufferOverrun::getBufferSize(const Token *bufTok) const if (var->isPointerArray()) v.intvalue = dim * mSettings->platform.sizeof_pointer; else { - const MathLib::bigint typeSize = bufTok->valueType()->typeSize(mSettings->platform); + const MathLib::bigint typeSize = bufTok->valueType()->getSizeOf(*mSettings, ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointee); v.intvalue = dim * typeSize; } @@ -929,7 +930,7 @@ bool CheckBufferOverrun::isCtuUnsafeBufferUsage(const Settings &settings, const { if (!offset) return false; - if (!argtok->valueType() || argtok->valueType()->typeSize(settings.platform) == 0) + if (!argtok->valueType() || argtok->valueType()->getSizeOf(settings, ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointee) == 0) return false; const Token *indexTok = nullptr; if (type == 1 && Token::Match(argtok, "%name% [") && argtok->astParent() == argtok->next() && !Token::simpleMatch(argtok->linkAt(1), "] [")) @@ -942,7 +943,7 @@ bool CheckBufferOverrun::isCtuUnsafeBufferUsage(const Settings &settings, const return false; if (!indexTok->hasKnownIntValue()) return false; - offset->value = indexTok->getKnownIntValue() * argtok->valueType()->typeSize(settings.platform); + offset->value = indexTok->getKnownIntValue() * argtok->valueType()->getSizeOf(settings, ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointee); return true; } @@ -1102,7 +1103,7 @@ void CheckBufferOverrun::objectIndex() continue; } if (obj->valueType() && var->valueType() && (obj->isCast() || (obj->isCpp() && isCPPCast(obj)) || obj->valueType()->pointer)) { // allow cast to a different type - const auto varSize = var->valueType()->typeSize(mSettings->platform); + const auto varSize = var->valueType()->getSizeOf(*mSettings, ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointee); if (varSize == 0) continue; if (obj->valueType()->type != var->valueType()->type) { diff --git a/lib/checkclass.cpp b/lib/checkclass.cpp index ec6c00b8dc4..95bfee0debc 100644 --- a/lib/checkclass.cpp +++ b/lib/checkclass.cpp @@ -3468,9 +3468,7 @@ void CheckClass::checkReturnByReference() const bool isView = isContainer && var->valueType()->container->view; bool warn = isContainer && !isView; if (!warn && !isView) { - const std::size_t size = ValueFlow::getSizeOf(*var->valueType(), - *mSettings, - ValueFlow::Accuracy::LowerBound); + const std::size_t size = var->valueType()->getSizeOf(*mSettings, ValueType::Accuracy::LowerBound, ValueType::SizeOf::Pointer); if (size > 2 * mSettings->platform.sizeof_pointer) warn = true; } diff --git a/lib/checkleakautovar.cpp b/lib/checkleakautovar.cpp index cf29a06a7fa..1eea2d176bb 100644 --- a/lib/checkleakautovar.cpp +++ b/lib/checkleakautovar.cpp @@ -1149,6 +1149,12 @@ void CheckLeakAutoVar::leakIfAllocated(const Token *vartok, } } +static bool isSafeCast(const ValueType* vt, const Settings& settings) +{ + const size_t sizeOf = vt->getSizeOf(settings, ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointee); + return sizeOf == 0 || sizeOf >= settings.platform.sizeof_pointer; +} + void CheckLeakAutoVar::ret(const Token *tok, VarInfo &varInfo, const bool isEndOfScope) { const std::map &alloctype = varInfo.alloctype; @@ -1180,9 +1186,7 @@ void CheckLeakAutoVar::ret(const Token *tok, VarInfo &varInfo, const bool isEndO const Token* tok3 = tok2->next(); while (tok3 && tok3->isCast() && tok3->valueType() && - (tok3->valueType()->pointer || - (tok3->valueType()->typeSize(mSettings->platform) == 0) || - (tok3->valueType()->typeSize(mSettings->platform) >= mSettings->platform.sizeof_pointer))) + (tok3->valueType()->pointer || isSafeCast(tok3->valueType(), *mSettings))) tok3 = tok3->astOperand2() ? tok3->astOperand2() : tok3->astOperand1(); if (tok3 && tok3->varId() == varid) tok2 = tok3->next(); diff --git a/lib/checkmemoryleak.cpp b/lib/checkmemoryleak.cpp index 024c2b5822d..4ba11a4bbc1 100644 --- a/lib/checkmemoryleak.cpp +++ b/lib/checkmemoryleak.cpp @@ -1065,8 +1065,8 @@ void CheckMemoryLeakNoVar::checkForUnreleasedInputArgument(const Scope *scope) const Variable* argvar = tok->function()->getArgumentVar(argnr); if (!argvar || !argvar->valueType()) continue; - const MathLib::bigint argSize = argvar->valueType()->typeSize(mSettings->platform, /*p*/ true); - if (argSize <= 0 || argSize >= mSettings->platform.sizeof_pointer) + const size_t argSize = argvar->valueType()->getSizeOf(*mSettings, ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointee); + if (argSize == 0 || argSize >= mSettings->platform.sizeof_pointer) continue; } functionCallLeak(arg, arg->str(), functionName); diff --git a/lib/checkother.cpp b/lib/checkother.cpp index 8dc8e81b0c4..1f8b9e9df5d 100644 --- a/lib/checkother.cpp +++ b/lib/checkother.cpp @@ -1524,7 +1524,7 @@ static bool isLargeContainer(const Variable* var, const Settings& settings) return false; } const ValueType vtElem = ValueType::parseDecl(vt->containerTypeToken, settings); - const auto elemSize = std::max(ValueFlow::getSizeOf(vtElem, settings, ValueFlow::Accuracy::LowerBound), 1); + const auto elemSize = std::max(vtElem.getSizeOf(settings, ValueType::Accuracy::LowerBound, ValueType::SizeOf::Pointer), 1); const auto arraySize = var->dimension(0) * elemSize; return arraySize > maxByValueSize; } @@ -1564,7 +1564,7 @@ void CheckOther::checkPassByReference() // Ensure that it is a large object. if (!var->type()->classScope) inconclusive = true; - else if (!var->valueType() || ValueFlow::getSizeOf(*var->valueType(), *mSettings, ValueFlow::Accuracy::LowerBound) <= 2 * mSettings->platform.sizeof_pointer) + else if (!var->valueType() || var->valueType()->getSizeOf(*mSettings, ValueType::Accuracy::LowerBound, ValueType::SizeOf::Pointer) <= 2 * mSettings->platform.sizeof_pointer) continue; } else @@ -3320,7 +3320,8 @@ void CheckOther::checkRedundantCopy() const Token* varTok = fScope->bodyEnd->tokAt(-2); if (varTok->variable() && !varTok->variable()->isGlobal() && (!varTok->variable()->type() || !varTok->variable()->type()->classScope || - (varTok->variable()->valueType() && ValueFlow::getSizeOf(*varTok->variable()->valueType(), *mSettings, ValueFlow::Accuracy::LowerBound) > 2 * mSettings->platform.sizeof_pointer))) + (varTok->variable()->valueType() && + varTok->variable()->valueType()->getSizeOf(*mSettings, ValueType::Accuracy::LowerBound, ValueType::SizeOf::Pointer) > 2 * mSettings->platform.sizeof_pointer))) redundantCopyError(startTok, startTok->str()); } } @@ -3440,7 +3441,7 @@ void CheckOther::checkIncompleteArrayFill() if (size == 0 && var->valueType()->pointer) size = mSettings->platform.sizeof_pointer; else if (size == 0 && var->valueType()) - size = ValueFlow::getSizeOf(*var->valueType(), *mSettings, ValueFlow::Accuracy::LowerBound); + size = var->valueType()->getSizeOf(*mSettings, ValueType::Accuracy::LowerBound, ValueType::SizeOf::Pointer); const Token* tok3 = tok->next()->astOperand2()->astOperand1()->astOperand1(); if ((size != 1 && size != 100 && size != 0) || var->isPointer()) { if (printWarning) @@ -4423,8 +4424,7 @@ static UnionMember parseUnionMember(const Variable &var, if (var.isArray()) { size = var.dimension(0); } else if (vt != nullptr) { - size = ValueFlow::getSizeOf(*vt, settings, - ValueFlow::Accuracy::ExactOrZero); + size = vt->getSizeOf(settings, ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointer); } return UnionMember(nameToken->str(), size); } @@ -4516,7 +4516,7 @@ static bool getBufAndOffset(const Token *expr, const Token *&buf, MathLib::bigin bufToken = expr->astOperand1()->astOperand1(); offsetToken = expr->astOperand1()->astOperand2(); if (expr->astOperand1()->valueType()) - elementSize = ValueFlow::getSizeOf(*expr->astOperand1()->valueType(), settings, ValueFlow::Accuracy::LowerBound); + elementSize = expr->astOperand1()->valueType()->getSizeOf(settings, ValueType::Accuracy::LowerBound, ValueType::SizeOf::Pointer); } else if (Token::Match(expr, "+|-") && expr->isBinaryOp()) { const bool pointer1 = (expr->astOperand1()->valueType() && expr->astOperand1()->valueType()->pointer > 0); const bool pointer2 = (expr->astOperand2()->valueType() && expr->astOperand2()->valueType()->pointer > 0); @@ -4525,13 +4525,13 @@ static bool getBufAndOffset(const Token *expr, const Token *&buf, MathLib::bigin offsetToken = expr->astOperand2(); auto vt = *expr->astOperand1()->valueType(); --vt.pointer; - elementSize = ValueFlow::getSizeOf(vt, settings, ValueFlow::Accuracy::LowerBound); + elementSize = vt.getSizeOf(settings, ValueType::Accuracy::LowerBound, ValueType::SizeOf::Pointer); } else if (!pointer1 && pointer2) { bufToken = expr->astOperand2(); offsetToken = expr->astOperand1(); auto vt = *expr->astOperand2()->valueType(); --vt.pointer; - elementSize = ValueFlow::getSizeOf(vt, settings, ValueFlow::Accuracy::LowerBound); + elementSize = vt.getSizeOf(settings, ValueType::Accuracy::LowerBound, ValueType::SizeOf::Pointer); } else { return false; } @@ -4540,7 +4540,7 @@ static bool getBufAndOffset(const Token *expr, const Token *&buf, MathLib::bigin *offset = 0; auto vt = *expr->valueType(); --vt.pointer; - elementSize = ValueFlow::getSizeOf(vt, settings, ValueFlow::Accuracy::LowerBound); + elementSize = vt.getSizeOf(settings, ValueType::Accuracy::LowerBound, ValueType::SizeOf::Pointer); if (elementSize > 0) { *offset *= elementSize; if (sizeValue) diff --git a/lib/checktype.cpp b/lib/checktype.cpp index 92d19c1e794..68b6580d270 100644 --- a/lib/checktype.cpp +++ b/lib/checktype.cpp @@ -322,12 +322,8 @@ static bool checkTypeCombination(ValueType src, ValueType tgt, const Settings& s src.reference = Reference::None; tgt.reference = Reference::None; - const std::size_t sizeSrc = ValueFlow::getSizeOf(src, - settings, - ValueFlow::Accuracy::ExactOrZero); - const std::size_t sizeTgt = ValueFlow::getSizeOf(tgt, - settings, - ValueFlow::Accuracy::ExactOrZero); + const std::size_t sizeSrc = src.getSizeOf(settings, ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointer); + const std::size_t sizeTgt = tgt.getSizeOf(settings, ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointer); if (!(sizeSrc > 0 && sizeTgt > 0 && sizeSrc < sizeTgt)) return false; diff --git a/lib/clangimport.cpp b/lib/clangimport.cpp index 9f3bf593755..c43ef84bcbf 100644 --- a/lib/clangimport.cpp +++ b/lib/clangimport.cpp @@ -1586,7 +1586,7 @@ static void setValues(const Tokenizer &tokenizer, const SymbolDatabase *symbolDa return v * dim.num; }); if (var.valueType()) - typeSize += mul * var.valueType()->typeSize(settings.platform, true); + typeSize += mul * var.valueType()->getSizeOf(settings, ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointer); } scope.definedType->sizeOf = typeSize; } @@ -1594,7 +1594,7 @@ static void setValues(const Tokenizer &tokenizer, const SymbolDatabase *symbolDa for (auto *tok = const_cast(tokenizer.tokens()); tok; tok = tok->next()) { if (Token::simpleMatch(tok, "sizeof (")) { ValueType vt = ValueType::parseDecl(tok->tokAt(2), settings); - const MathLib::bigint sz = vt.typeSize(settings.platform, true); + const MathLib::bigint sz = vt.getSizeOf(settings, ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointer); if (sz <= 0) continue; long long mul = 1; diff --git a/lib/ctu.cpp b/lib/ctu.cpp index 833a4dfda4b..aadba39d3c7 100644 --- a/lib/ctu.cpp +++ b/lib/ctu.cpp @@ -368,7 +368,7 @@ CTU::FileInfo *CTU::getFileInfo(const Tokenizer &tokenizer) functionCall.location = FileInfo::Location(tokenizer, tok); functionCall.callArgNr = argnr + 1; functionCall.callArgumentExpression = argtok->expressionString(); - const auto typeSize = argtok->valueType()->typeSize(tokenizer.getSettings().platform); + const auto typeSize = argtok->valueType()->getSizeOf(tokenizer.getSettings(), ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointee); functionCall.callArgValue.value = typeSize > 0 ? argtok->variable()->dimension(0) * typeSize : -1; functionCall.warning = false; fileInfo->functionCalls.push_back(std::move(functionCall)); @@ -382,7 +382,7 @@ CTU::FileInfo *CTU::getFileInfo(const Tokenizer &tokenizer) functionCall.location = FileInfo::Location(tokenizer, tok); functionCall.callArgNr = argnr + 1; functionCall.callArgumentExpression = argtok->expressionString(); - functionCall.callArgValue.value = argtok->astOperand1()->valueType()->typeSize(tokenizer.getSettings().platform); + functionCall.callArgValue.value = argtok->astOperand1()->valueType()->getSizeOf(tokenizer.getSettings(), ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointee); functionCall.warning = false; fileInfo->functionCalls.push_back(std::move(functionCall)); } diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index 5bb96a8cd4d..fb3fd06867d 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -45,6 +45,7 @@ #include #include #include +#include #include #include #include @@ -8436,40 +8437,187 @@ bool ValueType::isVolatile(nonneg int indirect) const return false; return volatileness & (1 << (pointer - indirect)); } -MathLib::bigint ValueType::typeSize(const Platform &platform, bool p) const + +namespace { + struct Result + { + size_t total; + bool success; + }; +} + +template +static Result accumulateStructMembers(const Scope* scope, F f, ValueType::Accuracy accuracy) { - if (p && pointer) - return platform.sizeof_pointer; + size_t total = 0; + std::set anonScopes; + for (const Variable& var : scope->varlist) { + if (var.isStatic()) + continue; + const MathLib::bigint bits = var.nameToken() ? var.nameToken()->bits() : -1; + if (const ValueType* vt = var.valueType()) { + if (vt->type == ValueType::Type::RECORD && vt->typeScope == scope) + return {0, false}; + const MathLib::bigint dim = std::accumulate(var.dimensions().cbegin(), var.dimensions().cend(), MathLib::bigint(1), [](MathLib::bigint i1, const Dimension& dim) { + return i1 * dim.num; + }); + if (var.nameToken()->scope() != scope && var.nameToken()->scope()->definedType) { // anonymous union + const auto ret = anonScopes.insert(var.nameToken()->scope()); + if (ret.second) + total = f(total, *vt, dim, bits); + } + else + total = f(total, *vt, dim, bits); + } + if (accuracy == ValueType::Accuracy::ExactOrZero && total == 0 && bits == -1) + return {0, false}; + } + return {total, true}; +} - if (typeScope && typeScope->definedType && typeScope->definedType->sizeOf) - return typeScope->definedType->sizeOf; - switch (type) { - case ValueType::Type::BOOL: - return platform.sizeof_bool; - case ValueType::Type::CHAR: +static size_t bitCeil(size_t x) +{ + if (x <= 1) return 1; - case ValueType::Type::SHORT: + --x; + x |= x >> 1; + x |= x >> 2; + x |= x >> 4; + x |= x >> 8; + x |= x >> 16; + x |= x >> 32; + return x + 1; +} + +static size_t getAlignOf(const ValueType& vt, const Settings& settings, ValueType::Accuracy accuracy, int maxRecursion = 0) +{ + if (maxRecursion == settings.vfOptions.maxAlignOfRecursion) { + // TODO: add bailout message + return 0; + } + if (vt.pointer || vt.reference != Reference::None || vt.isPrimitive()) { + auto align = vt.getSizeOf(settings, accuracy, ValueType::SizeOf::Pointer); + return align == 0 ? 0 : bitCeil(align); + } + if (vt.type == ValueType::Type::RECORD && vt.typeScope) { + auto accHelper = [&](size_t max, const ValueType& vt2, size_t /*dim*/, MathLib::bigint /*bits*/) { + size_t a = getAlignOf(vt2, settings, accuracy, ++maxRecursion); + return std::max(max, a); + }; + Result result = accumulateStructMembers(vt.typeScope, accHelper, accuracy); + 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; + return v; + }); + } + return result.success ? std::max(1, total) : total; + } + if (vt.type == ValueType::Type::CONTAINER) + return settings.platform.sizeof_pointer; // Just guess + return 0; +} + +size_t ValueType::getSizeOf( const Settings& settings, Accuracy accuracy, SizeOf sizeOf, int maxRecursion) const +{ + if (maxRecursion == settings.vfOptions.maxSizeOfRecursion) { + // TODO: add bailout message + return 0; + } + const auto& platform = settings.platform; + if (sizeOf == SizeOf::Pointer && (pointer || reference != Reference::None)) + return platform.sizeof_pointer; + if (type == ValueType::Type::BOOL || type == ValueType::Type::CHAR) + return 1; + if (type == ValueType::Type::SHORT) return platform.sizeof_short; - case ValueType::Type::WCHAR_T: + if (type == ValueType::Type::WCHAR_T) return platform.sizeof_wchar_t; - case ValueType::Type::INT: + if (type == ValueType::Type::INT) return platform.sizeof_int; - case ValueType::Type::LONG: + if (type == ValueType::Type::LONG) return platform.sizeof_long; - case ValueType::Type::LONGLONG: + if (type == ValueType::Type::LONGLONG) return platform.sizeof_long_long; - case ValueType::Type::FLOAT: + if (type == ValueType::Type::FLOAT) return platform.sizeof_float; - case ValueType::Type::DOUBLE: + if (type == ValueType::Type::DOUBLE) return platform.sizeof_double; - case ValueType::Type::LONGDOUBLE: + if (type == ValueType::Type::LONGDOUBLE) return platform.sizeof_long_double; - default: - break; + if (type == ValueType::Type::CONTAINER) + return 3 * platform.sizeof_pointer; // Just guess + if (type == ValueType::Type::RECORD && typeScope) { + size_t currentBitCount = 0; + size_t currentBitfieldAlloc = 0; + auto accHelper = [&](size_t total, const ValueType& vt2, size_t dim, MathLib::bigint bits) -> size_t { + const size_t charBit = settings.platform.char_bit; + size_t n = vt2.getSizeOf(settings, accuracy, SizeOf::Pointer, ++maxRecursion); + size_t a = getAlignOf(vt2, settings, accuracy); + if (n == 0 || a == 0) + return accuracy == Accuracy::ExactOrZero ? 0 : total; + if (bits == 0) { + if (currentBitfieldAlloc == 0) { + bits = n * charBit; + } else { + bits = (currentBitfieldAlloc * charBit) - currentBitCount; + } + } + if (bits > 0) { + size_t ret = total; + if (currentBitfieldAlloc == 0) { + currentBitfieldAlloc = n; + currentBitCount = 0; + } else if (currentBitCount + bits > charBit * currentBitfieldAlloc) { + ret += currentBitfieldAlloc; + currentBitfieldAlloc = n; + currentBitCount = 0; + } + while (bits > charBit * currentBitfieldAlloc) { + ret += currentBitfieldAlloc; + bits -= charBit * currentBitfieldAlloc; + } + currentBitCount += bits; + return ret; + } + n *= dim; + size_t padding = (a - (total % a)) % a; + if (currentBitCount > 0) { + bool fitsInBitfield = currentBitCount + (n * charBit) <= currentBitfieldAlloc * charBit; + bool isAligned = currentBitCount % (charBit * a) == 0; + if (vt2.isIntegral() && fitsInBitfield && isAligned) { + currentBitCount += charBit * n; + return total; + } + n += currentBitfieldAlloc; + currentBitfieldAlloc = 0; + currentBitCount = 0; + } + return typeScope->type == ScopeType::eUnion ? std::max(total, n) : total + padding + n; + }; + Result result = accumulateStructMembers(typeScope, accHelper, accuracy); + 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; + return v; + }); + } + if (accuracy == Accuracy::ExactOrZero && total == 0 && !result.success) + return 0; + total = std::max(size_t{1}, total); + size_t align = getAlignOf(*this, settings, accuracy); + if (align == 0) + return accuracy == Accuracy::ExactOrZero ? 0 : total; + total += (align - (total % align)) % align; + return total; } - - // Unknown invalid size return 0; } diff --git a/lib/symboldatabase.h b/lib/symboldatabase.h index 50f37fc1ebf..d221eb87da1 100644 --- a/lib/symboldatabase.h +++ b/lib/symboldatabase.h @@ -1312,7 +1312,15 @@ class CPPCHECKLIB ValueType { bool isVolatile(nonneg int indirect = 0) const; - MathLib::bigint typeSize(const Platform &platform, bool p=false) const; + enum class Accuracy : std::uint8_t { + ExactOrZero, + LowerBound, + }; + enum class SizeOf : std::uint8_t { + Pointer, + Pointee, + }; + size_t getSizeOf(const Settings& settings, Accuracy accuracy, SizeOf sizeOf, int maxRecursion = 0) const; /// Check if type is the same ignoring const and references bool isTypeEqual(const ValueType* that) const; diff --git a/lib/token.cpp b/lib/token.cpp index 0c64222801d..68e7838b6be 100644 --- a/lib/token.cpp +++ b/lib/token.cpp @@ -784,7 +784,7 @@ nonneg int Token::getStrSize(const Token *tok, const Settings &settings) if (tok->valueType()) { ValueType vt(*tok->valueType()); vt.pointer = 0; - sizeofType = ValueFlow::getSizeOf(vt, settings, ValueFlow::Accuracy::ExactOrZero); + sizeofType = vt.getSizeOf(settings, ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointer); } return getStrArraySize(tok) * sizeofType; } diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index 78a7a7c357a..6cae1f386f2 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -431,179 +431,6 @@ namespace { }; } -template -static Result accumulateStructMembers(const Scope* scope, F f, ValueFlow::Accuracy accuracy) -{ - size_t total = 0; - std::set anonScopes; - for (const Variable& var : scope->varlist) { - if (var.isStatic()) - continue; - const MathLib::bigint bits = var.nameToken() ? var.nameToken()->bits() : -1; - if (const ValueType* vt = var.valueType()) { - if (vt->type == ValueType::Type::RECORD && vt->typeScope == scope) - return {0, false}; - const MathLib::bigint dim = std::accumulate(var.dimensions().cbegin(), var.dimensions().cend(), MathLib::bigint(1), [](MathLib::bigint i1, const Dimension& dim) { - return i1 * dim.num; - }); - if (var.nameToken()->scope() != scope && var.nameToken()->scope()->definedType) { // anonymous union - const auto ret = anonScopes.insert(var.nameToken()->scope()); - if (ret.second) - total = f(total, *vt, dim, bits); - } - else - total = f(total, *vt, dim, bits); - } - if (accuracy == ValueFlow::Accuracy::ExactOrZero && total == 0 && bits == -1) - return {0, false}; - } - return {total, true}; -} - -static size_t bitCeil(size_t x) -{ - if (x <= 1) - return 1; - --x; - x |= x >> 1; - x |= x >> 2; - x |= x >> 4; - x |= x >> 8; - x |= x >> 16; - x |= x >> 32; - return x + 1; -} - -static size_t getAlignOf(const ValueType& vt, const Settings& settings, ValueFlow::Accuracy accuracy, int maxRecursion = 0) -{ - if (maxRecursion == settings.vfOptions.maxAlignOfRecursion) { - // TODO: add bailout message - return 0; - } - if (vt.pointer || vt.reference != Reference::None || vt.isPrimitive()) { - auto align = ValueFlow::getSizeOf(vt, settings, accuracy); - return align == 0 ? 0 : bitCeil(align); - } - if (vt.type == ValueType::Type::RECORD && vt.typeScope) { - auto accHelper = [&](size_t max, const ValueType& vt2, size_t /*dim*/, MathLib::bigint /*bits*/) { - size_t a = getAlignOf(vt2, settings, accuracy, ++maxRecursion); - return std::max(max, a); - }; - Result result = accumulateStructMembers(vt.typeScope, accHelper, accuracy); - 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; - return v; - }); - } - return result.success ? std::max(1, total) : total; - } - if (vt.type == ValueType::Type::CONTAINER) - return settings.platform.sizeof_pointer; // Just guess - return 0; -} - -size_t ValueFlow::getSizeOf(const ValueType &vt, const Settings &settings, Accuracy accuracy, int maxRecursion) -{ - if (maxRecursion == settings.vfOptions.maxSizeOfRecursion) { - // TODO: add bailout message - return 0; - } - if (vt.pointer || vt.reference != Reference::None) - return settings.platform.sizeof_pointer; - if (vt.type == ValueType::Type::BOOL || vt.type == ValueType::Type::CHAR) - return 1; - if (vt.type == ValueType::Type::SHORT) - return settings.platform.sizeof_short; - if (vt.type == ValueType::Type::WCHAR_T) - return settings.platform.sizeof_wchar_t; - if (vt.type == ValueType::Type::INT) - return settings.platform.sizeof_int; - if (vt.type == ValueType::Type::LONG) - return settings.platform.sizeof_long; - if (vt.type == ValueType::Type::LONGLONG) - return settings.platform.sizeof_long_long; - if (vt.type == ValueType::Type::FLOAT) - return settings.platform.sizeof_float; - if (vt.type == ValueType::Type::DOUBLE) - return settings.platform.sizeof_double; - if (vt.type == ValueType::Type::LONGDOUBLE) - return settings.platform.sizeof_long_double; - if (vt.type == ValueType::Type::CONTAINER) - return 3 * settings.platform.sizeof_pointer; // Just guess - if (vt.type == ValueType::Type::RECORD && vt.typeScope) { - size_t currentBitCount = 0; - size_t currentBitfieldAlloc = 0; - auto accHelper = [&](size_t total, const ValueType& vt2, size_t dim, MathLib::bigint bits) -> size_t { - const size_t charBit = settings.platform.char_bit; - size_t n = ValueFlow::getSizeOf(vt2, settings,accuracy, ++maxRecursion); - size_t a = getAlignOf(vt2, settings, accuracy); - if (n == 0 || a == 0) - return accuracy == Accuracy::ExactOrZero ? 0 : total; - if (bits == 0) { - if (currentBitfieldAlloc == 0) { - bits = n * charBit; - } else { - bits = (currentBitfieldAlloc * charBit) - currentBitCount; - } - } - if (bits > 0) { - size_t ret = total; - if (currentBitfieldAlloc == 0) { - currentBitfieldAlloc = n; - currentBitCount = 0; - } else if (currentBitCount + bits > charBit * currentBitfieldAlloc) { - ret += currentBitfieldAlloc; - currentBitfieldAlloc = n; - currentBitCount = 0; - } - while (bits > charBit * currentBitfieldAlloc) { - ret += currentBitfieldAlloc; - bits -= charBit * currentBitfieldAlloc; - } - currentBitCount += bits; - return ret; - } - n *= dim; - size_t padding = (a - (total % a)) % a; - if (currentBitCount > 0) { - bool fitsInBitfield = currentBitCount + (n * charBit) <= currentBitfieldAlloc * charBit; - bool isAligned = currentBitCount % (charBit * a) == 0; - if (vt2.isIntegral() && fitsInBitfield && isAligned) { - currentBitCount += charBit * n; - return total; - } - n += currentBitfieldAlloc; - currentBitfieldAlloc = 0; - currentBitCount = 0; - } - return vt.typeScope->type == ScopeType::eUnion ? std::max(total, n) : total + padding + n; - }; - Result result = accumulateStructMembers(vt.typeScope, accHelper, accuracy); - size_t total = result.total; - if (currentBitCount > 0) - total += currentBitfieldAlloc; - 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; - return v; - }); - } - if (accuracy == Accuracy::ExactOrZero && total == 0 && !result.success) - return 0; - total = std::max(size_t{1}, total); - size_t align = getAlignOf(vt, settings, accuracy); - if (align == 0) - return accuracy == Accuracy::ExactOrZero ? 0 : total; - total += (align - (total % align)) % align; - return total; - } - return 0; -} - static void valueFlowNumber(TokenList &tokenlist, const Settings& settings) { for (Token *tok = tokenlist.front(); tok;) { @@ -3683,8 +3510,8 @@ static bool isTruncated(const ValueType* src, const ValueType* dst, const Settin if (src->smartPointer && dst->smartPointer) return false; if ((src->isIntegral() && dst->isIntegral()) || (src->isFloat() && dst->isFloat())) { - const size_t srcSize = ValueFlow::getSizeOf(*src, settings, ValueFlow::Accuracy::LowerBound); - const size_t dstSize = ValueFlow::getSizeOf(*dst, settings, ValueFlow::Accuracy::LowerBound); + const size_t srcSize = src->getSizeOf(settings, ValueType::Accuracy::LowerBound, ValueType::SizeOf::Pointer); + const size_t dstSize = dst->getSizeOf(settings, ValueType::Accuracy::LowerBound, ValueType::SizeOf::Pointer); if (srcSize > dstSize) return true; if (srcSize == dstSize && src->sign != dst->sign) @@ -4207,10 +4034,10 @@ static std::list truncateValues(std::list va if (!dst || !dst->isIntegral()) return values; - const size_t sz = ValueFlow::getSizeOf(*dst, settings, ValueFlow::Accuracy::ExactOrZero); + const size_t sz = dst->getSizeOf(settings, ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointer); if (src) { - const size_t osz = ValueFlow::getSizeOf(*src, settings, ValueFlow::Accuracy::ExactOrZero); + const size_t osz = src->getSizeOf(settings, ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointer); if (osz >= sz && dst->sign == ValueType::Sign::SIGNED && src->sign == ValueType::Sign::UNSIGNED) { values.remove_if([&](const ValueFlow::Value& value) { if (!value.isIntValue()) @@ -7081,7 +6908,7 @@ static void valueFlowDynamicBufferSize(const TokenList& tokenlist, const SymbolD ValueType vt = *typeTok->valueType(); if (vt.pointer > 0) --vt.pointer; - const MathLib::bigint typeSize = ValueFlow::getSizeOf(vt, settings, ValueFlow::Accuracy::ExactOrZero); + const MathLib::bigint typeSize = vt.getSizeOf(settings, ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointer); if (typeSize > 0 || numElem == 0) sizeValue = numElem * typeSize; } diff --git a/lib/valueflow.h b/lib/valueflow.h index 85a8e49a9e7..6fe4d052fdf 100644 --- a/lib/valueflow.h +++ b/lib/valueflow.h @@ -61,16 +61,6 @@ namespace ValueFlow { std::string eitherTheConditionIsRedundant(const Token *condition); - enum class Accuracy : std::uint8_t { - ExactOrZero, - LowerBound, - }; - - size_t getSizeOf(const ValueType &vt, - const Settings &settings, - Accuracy accuracy, - int maxRecursion = 0); - const Value* findValue(const std::list& values, const Settings& settings, const std::function &pred); diff --git a/lib/vf_analyzers.cpp b/lib/vf_analyzers.cpp index 104563b113b..5f5568663e4 100644 --- a/lib/vf_analyzers.cpp +++ b/lib/vf_analyzers.cpp @@ -355,9 +355,7 @@ struct ValueFlowAnalyzer : Analyzer { /* Truncate value */ const ValueType *dst = tok->valueType(); if (dst) { - const size_t sz = ValueFlow::getSizeOf(*dst, - settings, - ValueFlow::Accuracy::ExactOrZero); + const size_t sz = dst->getSizeOf(settings, ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointer); if (sz > 0 && sz < sizeof(MathLib::biguint)) { MathLib::bigint newvalue = ValueFlow::truncateIntValue(value->intvalue, sz, dst->sign); diff --git a/lib/vf_common.cpp b/lib/vf_common.cpp index 0498a7e303d..56a6b364c44 100644 --- a/lib/vf_common.cpp +++ b/lib/vf_common.cpp @@ -114,7 +114,7 @@ namespace ValueFlow { const ValueType &valueType = ValueType::parseDecl(typeTok, settings); - return getSizeOf(valueType, settings, ValueFlow::Accuracy::ExactOrZero); + return valueType.getSizeOf(settings, ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointer); } // Handle various constants.. @@ -125,7 +125,7 @@ namespace ValueFlow MathLib::bigint signedValue = MathLib::toBigNumber(tok); const ValueType* vt = tok->valueType(); if (vt && vt->sign == ValueType::UNSIGNED && signedValue < 0 - && getSizeOf(*vt, settings, ValueFlow::Accuracy::ExactOrZero) + && vt->getSizeOf(settings, ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointer) < sizeof(MathLib::bigint)) { MathLib::bigint minValue{}, maxValue{}; if (getMinMaxValues(tok->valueType(), settings.platform, minValue, maxValue)) @@ -160,9 +160,7 @@ namespace ValueFlow (tok->next()->astOperand2()->valueType()->pointer == 0 || // <- TODO this is a bailout, abort when there are array->pointer conversions (tok->next()->astOperand2()->variable() && !tok->next()->astOperand2()->variable()->isArray())) && !tok->next()->astOperand2()->valueType()->isEnum()) { // <- TODO this is a bailout, handle enum with non-int types - const size_t sz = getSizeOf(*tok->next()->astOperand2()->valueType(), - settings, - ValueFlow::Accuracy::ExactOrZero); + const size_t sz = tok->next()->astOperand2()->valueType()->getSizeOf(settings, ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointer); if (sz) { Value value(sz); value.setKnown(); @@ -181,7 +179,7 @@ namespace ValueFlow } if (Token::simpleMatch(tok, "sizeof ( *")) { const ValueType *vt = tok->tokAt(2)->valueType(); - const size_t sz = vt ? getSizeOf(*vt, settings, ValueFlow::Accuracy::ExactOrZero) + const size_t sz = vt ? vt->getSizeOf(settings, ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointer) : 0; if (sz > 0) { Value value(sz); @@ -243,9 +241,7 @@ namespace ValueFlow if (var->type()->classScope && var->type()->classScope->enumType) size = getSizeOfType(var->type()->classScope->enumType, settings); } else if (var->valueType()) { - size = getSizeOf(*var->valueType(), - settings, - ValueFlow::Accuracy::ExactOrZero); + size = var->valueType()->getSizeOf(settings, ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointer); } else if (!var->type()) { size = getSizeOfType(var->typeStartToken(), settings); } @@ -294,7 +290,7 @@ namespace ValueFlow } } else if (!tok2->type()) { const ValueType& vt = ValueType::parseDecl(tok2, settings); - size_t sz = getSizeOf(vt, settings, ValueFlow::Accuracy::ExactOrZero); + size_t sz = vt.getSizeOf(settings, ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointer); const Token* brac = tok2->astParent(); while (Token::simpleMatch(brac, "[")) { const Token* num = brac->astOperand2(); diff --git a/lib/vf_settokenvalue.cpp b/lib/vf_settokenvalue.cpp index 0140b45ae06..4d39d35daae 100644 --- a/lib/vf_settokenvalue.cpp +++ b/lib/vf_settokenvalue.cpp @@ -83,8 +83,8 @@ namespace ValueFlow // If the sign is the same there is no truncation if (vt1->sign == vt2->sign) return value; - const size_t n1 = getSizeOf(*vt1, settings, ValueFlow::Accuracy::ExactOrZero); - const size_t n2 = getSizeOf(*vt2, settings, ValueFlow::Accuracy::ExactOrZero); + const size_t n1 = vt1->getSizeOf(settings, ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointer); + const size_t n2 = vt2->getSizeOf(settings, ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointer); ValueType::Sign sign = ValueType::Sign::UNSIGNED; if (n1 < n2) sign = vt2->sign; @@ -225,7 +225,7 @@ namespace ValueFlow { // Skip setting values that are too big since its ambiguous if (!value.isImpossible() && value.isIntValue() && value.intvalue < 0 && astIsUnsigned(tok) - && getSizeOf(*tok->valueType(), settings, ValueFlow::Accuracy::LowerBound) + && tok->valueType()->getSizeOf(settings, ValueType::Accuracy::LowerBound, ValueType::SizeOf::Pointer) >= sizeof(MathLib::bigint)) return; @@ -379,8 +379,8 @@ namespace ValueFlow const ValueType &valueType = ValueType::parseDecl(castType, settings); if (value.isImpossible() && value.isIntValue() && value.intvalue < 0 && astIsUnsigned(tok) && valueType.sign == ValueType::SIGNED && tok->valueType() - && getSizeOf(*tok->valueType(), settings, ValueFlow::Accuracy::ExactOrZero) - >= getSizeOf(valueType, settings, ValueFlow::Accuracy::ExactOrZero)) + && tok->valueType()->getSizeOf(settings, ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointer) + >= valueType.getSizeOf(settings, ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointer)) return; setTokenValueCast(parent, valueType, value, settings); } @@ -642,9 +642,7 @@ namespace ValueFlow if (v.isIntValue() || v.isSymbolicValue()) { const ValueType *dst = tok->valueType(); if (dst) { - const size_t sz = ValueFlow::getSizeOf(*dst, - settings, - ValueFlow::Accuracy::ExactOrZero); + const size_t sz = dst->getSizeOf(settings, ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointer); MathLib::bigint newvalue = ValueFlow::truncateIntValue(v.intvalue + 1, sz, dst->sign); if (v.bound != ValueFlow::Value::Bound::Point) { if (newvalue < v.intvalue) { @@ -674,9 +672,7 @@ namespace ValueFlow if (v.isIntValue() || v.isSymbolicValue()) { const ValueType *dst = tok->valueType(); if (dst) { - const size_t sz = ValueFlow::getSizeOf(*dst, - settings, - ValueFlow::Accuracy::ExactOrZero); + const size_t sz = dst->getSizeOf(settings, ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointer); MathLib::bigint newvalue = ValueFlow::truncateIntValue(v.intvalue - 1, sz, dst->sign); if (v.bound != ValueFlow::Value::Bound::Point) { if (newvalue > v.intvalue) { diff --git a/test/testmemleak.cpp b/test/testmemleak.cpp index 6e4e6cdf875..2280243ecab 100644 --- a/test/testmemleak.cpp +++ b/test/testmemleak.cpp @@ -2338,7 +2338,7 @@ class TestMemleakNoVar : public TestFixture { "void x() {\n" " set_error(strdup(p));\n" "}"); - TODO_ASSERT_EQUALS("[test.cpp:5]: (error) Allocation with strdup, set_error doesn't release it.\n", "", errout_str()); + ASSERT_EQUALS("[test.cpp:5:15]: (error) Allocation with strdup, set_error doesn't release it. [leakNoVarFunctionCall]\n", errout_str()); check("void f()\n" "{\n" From 73c95b54fbc744095f322a70f2f1e23a4b867198 Mon Sep 17 00:00:00 2001 From: chrchr-github Date: Mon, 8 Dec 2025 20:00:01 +0100 Subject: [PATCH 04/17] Fix --- lib/check64bit.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/check64bit.cpp b/lib/check64bit.cpp index eeda1c93648..309137af737 100644 --- a/lib/check64bit.cpp +++ b/lib/check64bit.cpp @@ -45,7 +45,7 @@ static bool is32BitIntegerReturn(const Function* func, const Settings* settings) if (settings->platform.sizeof_pointer != 8) return false; const ValueType* vt = func->arg->valueType(); - return vt && vt->pointer == 0 && vt->isIntegral() && vt->typeSize(settings->platform) == 4; + return vt && vt->pointer == 0 && vt->isIntegral() && vt->getSizeOf(*settings, ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointer) == 4; } void Check64BitPortability::pointerassignment() From 75a92a90a9457aed68731c0077a8120e6079f72f Mon Sep 17 00:00:00 2001 From: chrchr-github Date: Mon, 8 Dec 2025 20:02:47 +0100 Subject: [PATCH 05/17] Format --- lib/symboldatabase.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/symboldatabase.h b/lib/symboldatabase.h index d221eb87da1..a0e6190db73 100644 --- a/lib/symboldatabase.h +++ b/lib/symboldatabase.h @@ -1316,7 +1316,7 @@ class CPPCHECKLIB ValueType { ExactOrZero, LowerBound, }; - enum class SizeOf : std::uint8_t { + enum class SizeOf : std::uint8_t { Pointer, Pointee, }; From 3c9686af14b7621bff7217364ef89ed3181a50e8 Mon Sep 17 00:00:00 2001 From: chrchr-github Date: Mon, 8 Dec 2025 20:09:13 +0100 Subject: [PATCH 06/17] Rename --- lib/symboldatabase.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index 8f04433227b..0778fea205d 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -8555,34 +8555,34 @@ size_t ValueType::getSizeOf( const Settings& settings, Accuracy accuracy, SizeOf if (type == ValueType::Type::RECORD && typeScope) { size_t currentBitCount = 0; size_t currentBitfieldAlloc = 0; - auto accHelper = [&](size_t total, const ValueType& vt2, size_t dim, MathLib::bigint bits) -> size_t { + auto accHelper = [&](size_t total, const ValueType& vt2, size_t dim, MathLib::bigint nBits) -> size_t { const size_t charBit = settings.platform.char_bit; size_t n = vt2.getSizeOf(settings, accuracy, SizeOf::Pointer, ++maxRecursion); size_t a = getAlignOf(vt2, settings, accuracy); if (n == 0 || a == 0) return accuracy == Accuracy::ExactOrZero ? 0 : total; - if (bits == 0) { + if (nBits == 0) { if (currentBitfieldAlloc == 0) { - bits = n * charBit; + nBits = n * charBit; } else { - bits = (currentBitfieldAlloc * charBit) - currentBitCount; + nBits = (currentBitfieldAlloc * charBit) - currentBitCount; } } - if (bits > 0) { + if (nBits > 0) { size_t ret = total; if (currentBitfieldAlloc == 0) { currentBitfieldAlloc = n; currentBitCount = 0; - } else if (currentBitCount + bits > charBit * currentBitfieldAlloc) { + } else if (currentBitCount + nBits > charBit * currentBitfieldAlloc) { ret += currentBitfieldAlloc; currentBitfieldAlloc = n; currentBitCount = 0; } - while (bits > charBit * currentBitfieldAlloc) { + while (nBits > charBit * currentBitfieldAlloc) { ret += currentBitfieldAlloc; - bits -= charBit * currentBitfieldAlloc; + nBits -= charBit * currentBitfieldAlloc; } - currentBitCount += bits; + currentBitCount += nBits; return ret; } n *= dim; From 603c2e57186a2b0354569426bf3c8cd34966b7a3 Mon Sep 17 00:00:00 2001 From: chrchr-github Date: Mon, 8 Dec 2025 21:09:47 +0100 Subject: [PATCH 07/17] Remove --- lib/valueflow.cpp | 8 -------- 1 file changed, 8 deletions(-) diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index 6cae1f386f2..8a7ca9e43a4 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -423,14 +423,6 @@ void ValueFlow::combineValueProperties(const ValueFlow::Value &value1, const Val result.path = value1.path; } -namespace { - struct Result - { - size_t total; - bool success; - }; -} - static void valueFlowNumber(TokenList &tokenlist, const Settings& settings) { for (Token *tok = tokenlist.front(); tok;) { From 6e92c9ceba9bfdcff5228132870a90b1ca8b3eff Mon Sep 17 00:00:00 2001 From: chrchr-github Date: Mon, 8 Dec 2025 21:20:49 +0100 Subject: [PATCH 08/17] size_t --- lib/checkbufferoverrun.cpp | 4 ++-- lib/clangimport.cpp | 2 +- lib/valueflow.cpp | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/checkbufferoverrun.cpp b/lib/checkbufferoverrun.cpp index 9f9a00893db..0ee933da713 100644 --- a/lib/checkbufferoverrun.cpp +++ b/lib/checkbufferoverrun.cpp @@ -230,7 +230,7 @@ static bool getDimensionsEtc(const Token * const arrayToken, const Settings &set dim.known = value->isKnown(); dim.tok = nullptr; const auto sizeOf = array->valueType()->pointer > 1 ? ValueType::SizeOf::Pointer : ValueType::SizeOf::Pointee; - const MathLib::bigint typeSize = array->valueType()->getSizeOf(settings, ValueType::Accuracy::ExactOrZero, sizeOf); + const size_t typeSize = array->valueType()->getSizeOf(settings, ValueType::Accuracy::ExactOrZero, sizeOf); if (typeSize == 0) return false; dim.num = value->intvalue / typeSize; @@ -586,7 +586,7 @@ ValueFlow::Value CheckBufferOverrun::getBufferSize(const Token *bufTok) const if (var->isPointerArray()) v.intvalue = dim * mSettings->platform.sizeof_pointer; else { - const MathLib::bigint typeSize = bufTok->valueType()->getSizeOf(*mSettings, ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointee); + const size_t typeSize = bufTok->valueType()->getSizeOf(*mSettings, ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointee); v.intvalue = dim * typeSize; } diff --git a/lib/clangimport.cpp b/lib/clangimport.cpp index c43ef84bcbf..005714fe314 100644 --- a/lib/clangimport.cpp +++ b/lib/clangimport.cpp @@ -1594,7 +1594,7 @@ static void setValues(const Tokenizer &tokenizer, const SymbolDatabase *symbolDa for (auto *tok = const_cast(tokenizer.tokens()); tok; tok = tok->next()) { if (Token::simpleMatch(tok, "sizeof (")) { ValueType vt = ValueType::parseDecl(tok->tokAt(2), settings); - const MathLib::bigint sz = vt.getSizeOf(settings, ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointer); + const size_t sz = vt.getSizeOf(settings, ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointer); if (sz <= 0) continue; long long mul = 1; diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index 8a7ca9e43a4..f10396b2cad 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -6900,7 +6900,7 @@ static void valueFlowDynamicBufferSize(const TokenList& tokenlist, const SymbolD ValueType vt = *typeTok->valueType(); if (vt.pointer > 0) --vt.pointer; - const MathLib::bigint typeSize = vt.getSizeOf(settings, ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointer); + const size_t typeSize = vt.getSizeOf(settings, ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointer); if (typeSize > 0 || numElem == 0) sizeValue = numElem * typeSize; } From d25049006d7200610b399e75de507a029805426c Mon Sep 17 00:00:00 2001 From: chrchr-github Date: Mon, 8 Dec 2025 22:29:15 +0100 Subject: [PATCH 09/17] Fix --- lib/clangimport.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/clangimport.cpp b/lib/clangimport.cpp index 005714fe314..87877fd629e 100644 --- a/lib/clangimport.cpp +++ b/lib/clangimport.cpp @@ -1595,7 +1595,7 @@ static void setValues(const Tokenizer &tokenizer, const SymbolDatabase *symbolDa if (Token::simpleMatch(tok, "sizeof (")) { ValueType vt = ValueType::parseDecl(tok->tokAt(2), settings); const size_t sz = vt.getSizeOf(settings, ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointer); - if (sz <= 0) + if (sz == 0) continue; long long mul = 1; for (const Token *arrtok = tok->linkAt(1)->previous(); arrtok; arrtok = arrtok->previous()) { From 9dfef14271da01b3e0e71f8bbcbbeca29db6aa56 Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Tue, 9 Dec 2025 16:32:06 +0100 Subject: [PATCH 10/17] Update valueflow.cpp --- lib/valueflow.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index f10396b2cad..7b7ea7f2dbf 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -6897,10 +6897,7 @@ static void valueFlowDynamicBufferSize(const TokenList& tokenlist, const SymbolD if (!typeTok || !typeTok->varId()) typeTok = newTok->astParent()->previous(); // hack for "int** z = ..." if (typeTok && typeTok->valueType()) { - ValueType vt = *typeTok->valueType(); - if (vt.pointer > 0) - --vt.pointer; - const size_t typeSize = vt.getSizeOf(settings, ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointer); + const size_t typeSize = typeTok->valueType()->getSizeOf(settings, ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointee); if (typeSize > 0 || numElem == 0) sizeValue = numElem * typeSize; } From ccfb06b1f5bd49f702bada20522dd3cb81c77c51 Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Tue, 9 Dec 2025 16:43:45 +0100 Subject: [PATCH 11/17] Update valueflow.cpp --- lib/valueflow.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index 7b7ea7f2dbf..a4e24f5ca37 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -6897,7 +6897,8 @@ static void valueFlowDynamicBufferSize(const TokenList& tokenlist, const SymbolD if (!typeTok || !typeTok->varId()) typeTok = newTok->astParent()->previous(); // hack for "int** z = ..." if (typeTok && typeTok->valueType()) { - const size_t typeSize = typeTok->valueType()->getSizeOf(settings, ValueType::Accuracy::ExactOrZero, ValueType::SizeOf::Pointee); + const auto sizeOf = typeTok->valueType()->pointer > 1 ? ValueType::SizeOf::Pointer : ValueType::SizeOf::Pointee; + const size_t typeSize = typeTok->valueType()->getSizeOf(settings, ValueType::Accuracy::ExactOrZero, sizeOf); if (typeSize > 0 || numElem == 0) sizeValue = numElem * typeSize; } From 2790d08055d014bfb6e27bb7bb23946d3ded9c65 Mon Sep 17 00:00:00 2001 From: chrchr-github Date: Tue, 9 Dec 2025 18:59:44 +0100 Subject: [PATCH 12/17] Pass sizeOf to getAlignOf() --- lib/symboldatabase.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index 0778fea205d..522ef4dda8d 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -8492,19 +8492,19 @@ static size_t bitCeil(size_t x) return x + 1; } -static size_t getAlignOf(const ValueType& vt, const Settings& settings, ValueType::Accuracy accuracy, int maxRecursion = 0) +static size_t getAlignOf(const ValueType& vt, const Settings& settings, ValueType::Accuracy accuracy, ValueType::SizeOf sizeOf, int maxRecursion = 0) { if (maxRecursion == settings.vfOptions.maxAlignOfRecursion) { // TODO: add bailout message return 0; } - if (vt.pointer || vt.reference != Reference::None || vt.isPrimitive()) { + if ((vt.pointer && sizeOf == ValueType::SizeOf::Pointer) || vt.reference != Reference::None || vt.isPrimitive()) { auto align = vt.getSizeOf(settings, accuracy, ValueType::SizeOf::Pointer); return align == 0 ? 0 : bitCeil(align); } if (vt.type == ValueType::Type::RECORD && vt.typeScope) { auto accHelper = [&](size_t max, const ValueType& vt2, size_t /*dim*/, MathLib::bigint /*bits*/) { - size_t a = getAlignOf(vt2, settings, accuracy, ++maxRecursion); + size_t a = getAlignOf(vt2, settings, accuracy, sizeOf, ++maxRecursion); return std::max(max, a); }; Result result = accumulateStructMembers(vt.typeScope, accHelper, accuracy); @@ -8558,7 +8558,7 @@ size_t ValueType::getSizeOf( const Settings& settings, Accuracy accuracy, SizeOf auto accHelper = [&](size_t total, const ValueType& vt2, size_t dim, MathLib::bigint nBits) -> size_t { const size_t charBit = settings.platform.char_bit; size_t n = vt2.getSizeOf(settings, accuracy, SizeOf::Pointer, ++maxRecursion); - size_t a = getAlignOf(vt2, settings, accuracy); + size_t a = getAlignOf(vt2, settings, accuracy, SizeOf::Pointer); if (n == 0 || a == 0) return accuracy == Accuracy::ExactOrZero ? 0 : total; if (nBits == 0) { @@ -8614,7 +8614,7 @@ size_t ValueType::getSizeOf( const Settings& settings, Accuracy accuracy, SizeOf if (accuracy == Accuracy::ExactOrZero && total == 0 && !result.success) return 0; total = std::max(size_t{1}, total); - size_t align = getAlignOf(*this, settings, accuracy); + size_t align = getAlignOf(*this, settings, accuracy, sizeOf); if (align == 0) return accuracy == Accuracy::ExactOrZero ? 0 : total; total += (align - (total % align)) % align; From c1bb38474b95c0b69d9a943da1fe5ff45dc8bfac Mon Sep 17 00:00:00 2001 From: chrchr-github Date: Tue, 9 Dec 2025 21:31:05 +0100 Subject: [PATCH 13/17] Fix --- lib/symboldatabase.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index 522ef4dda8d..47145f2191d 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -8504,7 +8504,7 @@ static size_t getAlignOf(const ValueType& vt, const Settings& settings, ValueTyp } if (vt.type == ValueType::Type::RECORD && vt.typeScope) { auto accHelper = [&](size_t max, const ValueType& vt2, size_t /*dim*/, MathLib::bigint /*bits*/) { - size_t a = getAlignOf(vt2, settings, accuracy, sizeOf, ++maxRecursion); + size_t a = getAlignOf(vt2, settings, accuracy, ValueType::SizeOf::Pointer, ++maxRecursion); return std::max(max, a); }; Result result = accumulateStructMembers(vt.typeScope, accHelper, accuracy); From 724fe1dd42985a508b98c8cf0ff353079783f3e5 Mon Sep 17 00:00:00 2001 From: chrchr-github Date: Tue, 9 Dec 2025 21:43:33 +0100 Subject: [PATCH 14/17] Add TODO --- test/testvalueflow.cpp | 53 ++++++++++++++---------------------------- 1 file changed, 18 insertions(+), 35 deletions(-) diff --git a/test/testvalueflow.cpp b/test/testvalueflow.cpp index d7b05bc6af4..c73b9e593c8 100644 --- a/test/testvalueflow.cpp +++ b/test/testvalueflow.cpp @@ -1726,6 +1726,22 @@ class TestValueFlow : public TestFixture { ASSERT_EQUALS(1U, values.size()); ASSERT_EQUALS(-1, values.back().intvalue); ASSERT_EQUALS_ENUM(ValueFlow::Value::ValueKind::Impossible, values.back().valueKind); + + code = "struct E;\n" + "struct B {\n" + " E* e;\n" + " B* b;\n" + "};\n" + "struct D : B {};\n" + "struct E : B {\n" + " B* be;\n" + "};\n" + "int f() {\n" + " return sizeof(D);\n" + "}"; + values = tokenValues(code, "( D )"); + ASSERT_EQUALS(1U, values.size()); + TODO_ASSERT_EQUALS(2 * settings.platform.sizeof_pointer, 1, values.back().intvalue); } void valueFlowComma() @@ -7457,32 +7473,6 @@ class TestValueFlow : public TestFixture { "}"; ASSERT_EQUALS(true, testValueOfX(code, 4U, 100, ValueFlow::Value::ValueType::BUFFER_SIZE)); - code = "struct A {};\n" // #14305 - "void* f() {\n" - " A* x = new A();\n" - " return x;\n" - "}"; - ASSERT_EQUALS(true, testValueOfX(code, 4U, 1, ValueFlow::Value::ValueType::BUFFER_SIZE)); - - code = "struct A {};\n" - "void* f() {\n" - " void* x = new A;\n" - " return x;\n" - "}"; - { - auto values = tokenValues(code, "x ; }"); - ASSERT_EQUALS(1, values.size()); - ASSERT(values.front().isSymbolicValue()); - // TODO: add BUFFER_SIZE value = 1 - } - - code = "struct B { int32_t i; };\n" - "void* f() {\n" - " B* x = new B();\n" - " return x;\n" - "}"; - ASSERT_EQUALS(true, testValueOfX(code, 4U, 4, ValueFlow::Value::ValueType::BUFFER_SIZE)); - settings = settingsOld; } @@ -9092,8 +9082,8 @@ class TestValueFlow : public TestFixture { ASSERT_EQUALS(false, testValueOfX(code, 5U, 0)); } - void valueFlowBailoutIncompleteVar() { - bailout( // #12526 + void valueFlowBailoutIncompleteVar() { // #12526 + bailout( "int f1() {\n" " return VALUE_1;\n" "}\n" @@ -9106,13 +9096,6 @@ class TestValueFlow : public TestFixture { "[test.cpp:2]: (debug) valueFlowConditionExpressions bailout: Skipping function due to incomplete variable VALUE_1\n" "[test.cpp:6]: (debug) valueFlowConditionExpressions bailout: Skipping function due to incomplete variable VALUE_2\n", errout_str()); - - bailout( - "std::string_view f() {\n" - " return \"abc\"sv;\n" - "}\n" - ); - ASSERT_EQUALS_WITHOUT_LINENUMBERS("", errout_str()); } void valueFlowBailoutNoreturn() { // #13718 From 08a8b7c5f2c0359fbd8d8fd7ec482f3637ce9aaf Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Wed, 10 Dec 2025 09:01:21 +0100 Subject: [PATCH 15/17] Try to fix SonarQube issue --- lib/checkbufferoverrun.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/checkbufferoverrun.cpp b/lib/checkbufferoverrun.cpp index 0ee933da713..57c46492bc0 100644 --- a/lib/checkbufferoverrun.cpp +++ b/lib/checkbufferoverrun.cpp @@ -96,7 +96,7 @@ static int getMinFormatStringOutputLength(const std::vector ¶m std::string digits_string; bool i_d_x_f_found = false; int parameterLength = 0; - int inputArgNr = formatStringArgNr; + nonneg int inputArgNr = formatStringArgNr; for (std::size_t i = 1; i + 1 < formatString.length(); ++i) { if (formatString[i] == '\\') { if (i < formatString.length() - 1 && formatString[i + 1] == '0') From cfc1fdae3cb6d29c5bb15fd72a693f1b9597cd38 Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Wed, 10 Dec 2025 13:56:59 +0100 Subject: [PATCH 16/17] Undo/restore --- test/testvalueflow.cpp | 37 +++++++++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/test/testvalueflow.cpp b/test/testvalueflow.cpp index c73b9e593c8..acad2617810 100644 --- a/test/testvalueflow.cpp +++ b/test/testvalueflow.cpp @@ -7473,6 +7473,32 @@ class TestValueFlow : public TestFixture { "}"; ASSERT_EQUALS(true, testValueOfX(code, 4U, 100, ValueFlow::Value::ValueType::BUFFER_SIZE)); + code = "struct A {};\n" // #14305 + "void* f() {\n" + " A* x = new A();\n" + " return x;\n" + "}"; + ASSERT_EQUALS(true, testValueOfX(code, 4U, 1, ValueFlow::Value::ValueType::BUFFER_SIZE)); + + code = "struct A {};\n" + "void* f() {\n" + " void* x = new A;\n" + " return x;\n" + "}"; + { + auto values = tokenValues(code, "x ; }"); + ASSERT_EQUALS(1, values.size()); + ASSERT(values.front().isSymbolicValue()); + // TODO: add BUFFER_SIZE value = 1 + } + + code = "struct B { int32_t i; };\n" + "void* f() {\n" + " B* x = new B();\n" + " return x;\n" + "}"; + ASSERT_EQUALS(true, testValueOfX(code, 4U, 4, ValueFlow::Value::ValueType::BUFFER_SIZE)); + settings = settingsOld; } @@ -9082,8 +9108,8 @@ class TestValueFlow : public TestFixture { ASSERT_EQUALS(false, testValueOfX(code, 5U, 0)); } - void valueFlowBailoutIncompleteVar() { // #12526 - bailout( + void valueFlowBailoutIncompleteVar() { + bailout( // #12526 "int f1() {\n" " return VALUE_1;\n" "}\n" @@ -9096,6 +9122,13 @@ class TestValueFlow : public TestFixture { "[test.cpp:2]: (debug) valueFlowConditionExpressions bailout: Skipping function due to incomplete variable VALUE_1\n" "[test.cpp:6]: (debug) valueFlowConditionExpressions bailout: Skipping function due to incomplete variable VALUE_2\n", errout_str()); + + bailout( + "std::string_view f() {\n" + " return \"abc\"sv;\n" + "}\n" + ); + ASSERT_EQUALS_WITHOUT_LINENUMBERS("", errout_str()); } void valueFlowBailoutNoreturn() { // #13718 From 572a876638dc251cf797d4d2c860a6e9727fc965 Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Wed, 10 Dec 2025 14:05:35 +0100 Subject: [PATCH 17/17] Format --- test/testvalueflow.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test/testvalueflow.cpp b/test/testvalueflow.cpp index acad2617810..79ad6e45b30 100644 --- a/test/testvalueflow.cpp +++ b/test/testvalueflow.cpp @@ -7485,12 +7485,12 @@ class TestValueFlow : public TestFixture { " void* x = new A;\n" " return x;\n" "}"; - { - auto values = tokenValues(code, "x ; }"); - ASSERT_EQUALS(1, values.size()); - ASSERT(values.front().isSymbolicValue()); - // TODO: add BUFFER_SIZE value = 1 - } + { + auto values = tokenValues(code, "x ; }"); + ASSERT_EQUALS(1, values.size()); + ASSERT(values.front().isSymbolicValue()); + // TODO: add BUFFER_SIZE value = 1 + } code = "struct B { int32_t i; };\n" "void* f() {\n"