Skip to content

Commit f87363d

Browse files
pfultz2Your Name
andauthored
Fix 14924: FP containerOutOfBounds (copy accessed in loop) (#8740)
Co-authored-by: Your Name <you@example.com>
1 parent e0e5a04 commit f87363d

2 files changed

Lines changed: 39 additions & 2 deletions

File tree

lib/programmemory.cpp

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1512,6 +1512,31 @@ namespace {
15121512
return unknown();
15131513
}
15141514

1515+
// Get the size of the container. If the container itself is not tracked in the program
1516+
// memory then check if it is symbolically equal to a container whose size is tracked.
1517+
ValueFlow::Value executeContainerSize(const Token* containerTok)
1518+
{
1519+
ValueFlow::Value v = execute(containerTok);
1520+
if (v.isContainerSizeValue())
1521+
return v;
1522+
for (const ValueFlow::Value& value : containerTok->values()) {
1523+
if (!value.isSymbolicValue())
1524+
continue;
1525+
if (value.isImpossible())
1526+
continue;
1527+
if (value.intvalue != 0)
1528+
continue;
1529+
if (!value.tokvalue)
1530+
continue;
1531+
if (value.tokvalue->exprId() == 0)
1532+
continue;
1533+
const ValueFlow::Value* sizeValue = pm->getValue(value.tokvalue->exprId());
1534+
if (sizeValue && sizeValue->isContainerSizeValue())
1535+
return *sizeValue;
1536+
}
1537+
return unknown();
1538+
}
1539+
15151540
ValueFlow::Value executeImpl(const Token* expr)
15161541
{
15171542
const ValueFlow::Value* value = nullptr;
@@ -1540,14 +1565,14 @@ namespace {
15401565
const Token* containerTok = expr->tokAt(-2)->astOperand1();
15411566
const Library::Container::Yield yield = containerTok->valueType()->container->getYield(expr->strAt(-1));
15421567
if (yield == Library::Container::Yield::SIZE) {
1543-
ValueFlow::Value v = execute(containerTok);
1568+
ValueFlow::Value v = executeContainerSize(containerTok);
15441569
if (!v.isContainerSizeValue())
15451570
return unknown();
15461571
v.valueType = ValueFlow::Value::ValueType::INT;
15471572
return v;
15481573
}
15491574
if (yield == Library::Container::Yield::EMPTY) {
1550-
ValueFlow::Value v = execute(containerTok);
1575+
ValueFlow::Value v = executeContainerSize(containerTok);
15511576
if (!v.isContainerSizeValue())
15521577
return unknown();
15531578
if (v.isImpossible() && v.intvalue == 0)

test/teststl.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1003,6 +1003,18 @@ class TestStl : public TestFixture {
10031003
"}\n");
10041004
ASSERT_EQUALS("[test.cpp:2:13]: error: Out of bounds access in 'v[2]', if 'v' size is 1 and '2' is 2 [containerOutOfBounds]\n",
10051005
errout_str());
1006+
1007+
checkNormal("std::string f(const std::string& str) {\n" // do not warn, the copy has the same size as 'str'
1008+
" std::string outStr = str;\n"
1009+
" if (!outStr.empty())\n"
1010+
" outStr[0] = 'a';\n"
1011+
" for (int i = 0; i < str.size(); ++i) {\n"
1012+
" if (outStr[i] == '_')\n"
1013+
" outStr[i] = ' ';\n"
1014+
" }\n"
1015+
" return outStr;\n"
1016+
"}\n");
1017+
ASSERT_EQUALS("", errout_str());
10061018
}
10071019

10081020
void outOfBoundsSymbolic()

0 commit comments

Comments
 (0)