diff --git a/lib/checkother.cpp b/lib/checkother.cpp index 6c8abb1f4b1..7b9791fe8c4 100644 --- a/lib/checkother.cpp +++ b/lib/checkother.cpp @@ -1307,6 +1307,25 @@ void CheckOther::commaSeparatedReturnError(const Token *tok) "macro is then used in a return statement, it is less likely such code is misunderstood.", CWE398, Certainty::normal); } +static bool isLargeContainer(const Variable* var, const Settings* settings) +{ + const ValueType* vt = var->valueType(); + if (vt->container->size_templateArgNo < 0) + return true; + const std::size_t maxByValueSize = 2 * settings->platform.sizeof_pointer; + if (var->dimensions().empty()) { + if (vt->container->startPattern == "std :: bitset <") { + if (vt->containerTypeToken->hasKnownIntValue()) + return vt->containerTypeToken->getKnownIntValue() / 8 > maxByValueSize; + } + return false; + } + const ValueType vtElem = ValueType::parseDecl(vt->containerTypeToken, *settings); + const auto elemSize = std::max(ValueFlow::getSizeOf(vtElem, *settings), 1); + const auto arraySize = var->dimension(0) * elemSize; + return arraySize > maxByValueSize; +} + void CheckOther::checkPassByReference() { if (!mSettings->severity.isEnabled(Severity::performance) || mTokenizer->isC()) @@ -1317,7 +1336,7 @@ void CheckOther::checkPassByReference() const SymbolDatabase * const symbolDatabase = mTokenizer->getSymbolDatabase(); for (const Variable* var : symbolDatabase->variableList()) { - if (!var || !var->isClass() || var->isPointer() || var->isArray() || var->isReference() || var->isEnumType()) + if (!var || !var->isClass() || var->isPointer() || (var->isArray() && !var->isStlType()) || var->isReference() || var->isEnumType()) continue; const bool isRangeBasedFor = astIsRangeBasedForDecl(var->nameToken()); @@ -1335,6 +1354,8 @@ void CheckOther::checkPassByReference() bool inconclusive = false; const bool isContainer = var->valueType() && var->valueType()->type == ValueType::Type::CONTAINER && var->valueType()->container && !var->valueType()->container->view; + if (isContainer && !isLargeContainer(var, mSettings)) + continue; if (!isContainer) { if (var->type() && !var->type()->isEnumType()) { // Check if type is a struct or class. // Ensure that it is a large object. diff --git a/test/cfg/std.cpp b/test/cfg/std.cpp index 516099bdf9c..e2fc85ab95a 100644 --- a/test/cfg/std.cpp +++ b/test/cfg/std.cpp @@ -5137,3 +5137,25 @@ void unusedvar_stringstream(const char* p) // cppcheck-suppress unreadVariable std::stringstream sstr(p); } + +int passedByValue_std_array1(std::array a) +{ + return a[0] + a[1]; +} + +// cppcheck-suppress passedByValue +int passedByValue_std_array2(std::array a) +{ + return a[0] + a[1]; +} + +int passedByValue_std_bitset1(std::bitset<4> bs) // #12961 +{ + return bs.size(); +} + +// cppcheck-suppress passedByValue +int passedByValue_std_bitset2(std::bitset<256> bs) +{ + return bs.size(); +}