Skip to content

Commit b80e242

Browse files
authored
Fix 10604: FP mismatchingContainerIterator with container member (#3575)
1 parent c7ef602 commit b80e242

2 files changed

Lines changed: 63 additions & 16 deletions

File tree

lib/checkstl.cpp

Lines changed: 45 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -697,14 +697,47 @@ static const Token * getIteratorExpression(const Token * tok)
697697
return nullptr;
698698
}
699699

700+
static const Token* getAddressContainer(const Token* tok)
701+
{
702+
if (Token::simpleMatch(tok, "[") && tok->astOperand1())
703+
return tok->astOperand1();
704+
return tok;
705+
}
706+
707+
static bool isSameIteratorContainerExpression(const Token* tok1,
708+
const Token* tok2,
709+
const Library& library,
710+
ValueFlow::Value::LifetimeKind kind = ValueFlow::Value::LifetimeKind::Iterator)
711+
{
712+
if (isSameExpression(true, false, tok1, tok2, library, false, false))
713+
return true;
714+
if (kind == ValueFlow::Value::LifetimeKind::Address) {
715+
return isSameExpression(true, false, getAddressContainer(tok1), getAddressContainer(tok2), library, false, false);
716+
}
717+
return false;
718+
}
719+
720+
static ValueFlow::Value getLifetimeIteratorValue(const Token* tok)
721+
{
722+
std::vector<ValueFlow::Value> values = getLifetimeObjValues(tok);
723+
auto it = std::find_if(values.begin(), values.end(), [](const ValueFlow::Value& v) {
724+
return v.lifetimeKind == ValueFlow::Value::LifetimeKind::Iterator;
725+
});
726+
if (it != values.end())
727+
return *it;
728+
if (values.size() == 1)
729+
return values.front();
730+
return ValueFlow::Value{};
731+
}
732+
700733
bool CheckStl::checkIteratorPair(const Token* tok1, const Token* tok2)
701734
{
702735
if (!tok1)
703736
return false;
704737
if (!tok2)
705738
return false;
706-
ValueFlow::Value val1 = getLifetimeObjValue(tok1);
707-
ValueFlow::Value val2 = getLifetimeObjValue(tok2);
739+
ValueFlow::Value val1 = getLifetimeIteratorValue(tok1);
740+
ValueFlow::Value val2 = getLifetimeIteratorValue(tok2);
708741
if (val1.tokvalue && val2.tokvalue && val1.lifetimeKind == val2.lifetimeKind) {
709742
if (val1.lifetimeKind == ValueFlow::Value::LifetimeKind::Lambda)
710743
return false;
@@ -715,7 +748,7 @@ bool CheckStl::checkIteratorPair(const Token* tok1, const Token* tok2)
715748
(!astIsContainer(val1.tokvalue) || !astIsContainer(val2.tokvalue)))
716749
return false;
717750
}
718-
if (isSameExpression(true, false, val1.tokvalue, val2.tokvalue, mSettings->library, false, false))
751+
if (isSameIteratorContainerExpression(val1.tokvalue, val2.tokvalue, mSettings->library, val1.lifetimeKind))
719752
return false;
720753
if (val1.tokvalue->expressionString() == val2.tokvalue->expressionString())
721754
iteratorsError(tok1, val1.tokvalue, val1.tokvalue->expressionString());
@@ -731,7 +764,7 @@ bool CheckStl::checkIteratorPair(const Token* tok1, const Token* tok2)
731764
}
732765
const Token* iter1 = getIteratorExpression(tok1);
733766
const Token* iter2 = getIteratorExpression(tok2);
734-
if (iter1 && iter2 && !isSameExpression(true, false, iter1, iter2, mSettings->library, false, false)) {
767+
if (iter1 && iter2 && !isSameIteratorContainerExpression(iter1, iter2, mSettings->library)) {
735768
mismatchingContainerExpressionError(iter1, iter2);
736769
return true;
737770
}
@@ -808,9 +841,11 @@ void CheckStl::mismatchingContainerIterator()
808841
for (const Token* tok = scope->bodyStart->next(); tok != scope->bodyEnd; tok = tok->next()) {
809842
if (!astIsContainer(tok))
810843
continue;
811-
if (!Token::Match(tok, "%var% . %name% ( !!)"))
844+
if (!astIsLHS(tok))
845+
continue;
846+
if (!Token::Match(tok->astParent(), ". %name% ( !!)"))
812847
continue;
813-
const Token * const ftok = tok->tokAt(2);
848+
const Token* const ftok = tok->astParent()->next();
814849
const std::vector<const Token *> args = getArguments(ftok);
815850

816851
const Library::Container * c = tok->valueType()->container;
@@ -831,20 +866,14 @@ void CheckStl::mismatchingContainerIterator()
831866
continue;
832867
}
833868

834-
ValueFlow::Value val = getLifetimeObjValue(iterTok);
869+
ValueFlow::Value val = getLifetimeIteratorValue(iterTok);
835870
if (!val.tokvalue)
836871
continue;
837872
if (val.lifetimeKind != ValueFlow::Value::LifetimeKind::Iterator)
838873
continue;
839-
for (const LifetimeToken& lt:getLifetimeTokens(tok)) {
840-
if (lt.inconclusive)
841-
continue;
842-
const Token* contTok = lt.token;
843-
if (isSameExpression(true, false, contTok, val.tokvalue, mSettings->library, false, false))
844-
continue;
845-
mismatchingContainerIteratorError(tok, iterTok);
846-
}
847-
874+
if (isSameIteratorContainerExpression(tok, val.tokvalue, mSettings->library))
875+
continue;
876+
mismatchingContainerIteratorError(tok, iterTok);
848877
}
849878
}
850879
}

test/teststl.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1658,6 +1658,15 @@ class TestStl : public TestFixture {
16581658
" if(f().begin(1) == f().end()) {}\n"
16591659
"}");
16601660
ASSERT_EQUALS("", errout.str());
1661+
1662+
check("void foo(const uint8_t* data, const uint32_t dataLength) {\n"
1663+
" const uint32_t minimumLength = sizeof(uint16_t) + sizeof(uint16_t);\n"
1664+
" if (dataLength >= minimumLength) {\n"
1665+
" char* payload = new char[dataLength - minimumLength];\n"
1666+
" std::copy(&data[minimumLength], &data[dataLength], payload);\n"
1667+
" }\n"
1668+
"}\n");
1669+
ASSERT_EQUALS("", errout.str());
16611670
}
16621671

16631672
void iteratorSameExpression() {
@@ -1742,6 +1751,15 @@ class TestStl : public TestFixture {
17421751
" }\n"
17431752
"}\n");
17441753
ASSERT_EQUALS("", errout.str());
1754+
1755+
// #10604
1756+
check("struct S {\n"
1757+
" std::vector<int> v;\n"
1758+
"};\n"
1759+
"void f(S& s, int m) {\n"
1760+
" s.v.erase(s.v.begin() + m);\n"
1761+
"}\n");
1762+
ASSERT_EQUALS("", errout.str());
17451763
}
17461764

17471765
// Dereferencing invalid pointer

0 commit comments

Comments
 (0)