Skip to content

Commit

Permalink
Fix #12961 FP passedByValue with std::bitset (danmar#6635)
Browse files Browse the repository at this point in the history
  • Loading branch information
chrchr-github committed Jul 24, 2024
1 parent 30a32dd commit d37f463
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 1 deletion.
23 changes: 22 additions & 1 deletion lib/checkother.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<std::size_t>(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())
Expand All @@ -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());
Expand All @@ -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.
Expand Down
22 changes: 22 additions & 0 deletions test/cfg/std.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5137,3 +5137,25 @@ void unusedvar_stringstream(const char* p)
// cppcheck-suppress unreadVariable
std::stringstream sstr(p);
}

int passedByValue_std_array1(std::array<int, 2> a)
{
return a[0] + a[1];
}

// cppcheck-suppress passedByValue
int passedByValue_std_array2(std::array<int, 200> 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();
}

0 comments on commit d37f463

Please sign in to comment.