diff options
| -rw-r--r-- | clang/lib/StaticAnalyzer/Checkers/IteratorChecker.cpp | 49 | ||||
| -rw-r--r-- | clang/test/Analysis/mismatched-iterator.cpp | 14 |
2 files changed, 60 insertions, 3 deletions
diff --git a/clang/lib/StaticAnalyzer/Checkers/IteratorChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/IteratorChecker.cpp index 8649a32f054..38e9f22675f 100644 --- a/clang/lib/StaticAnalyzer/Checkers/IteratorChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/IteratorChecker.cpp @@ -1098,14 +1098,34 @@ void IteratorChecker::verifyMatch(CheckerContext &C, const SVal &Iter, // Verify match between a container and the container of an iterator Cont = Cont->getMostDerivedObjectRegion(); + if (const auto *ContSym = Cont->getSymbolicBase()) { + if (isa<SymbolConjured>(ContSym->getSymbol())) + return; + } + auto State = C.getState(); const auto *Pos = getIteratorPosition(State, Iter); - if (Pos && Pos->getContainer() != Cont) { + if (!Pos) + return; + + const auto *IterCont = Pos->getContainer(); + + // Skip symbolic regions based on conjured symbols. Two conjured symbols + // may or may not be the same. For example, the same function can return + // the same or a different container but we get different conjured symbols + // for each call. This may cause false positives so omit them from the check. + if (const auto *ContSym = IterCont->getSymbolicBase()) { + if (isa<SymbolConjured>(ContSym->getSymbol())) + return; + } + + if (IterCont != Cont) { auto *N = C.generateNonFatalErrorNode(State); if (!N) { return; } - reportMismatchedBug("Container accessed using foreign iterator argument.", Iter, Cont, C, N); + reportMismatchedBug("Container accessed using foreign iterator argument.", + Iter, Cont, C, N); } } @@ -1114,8 +1134,31 @@ void IteratorChecker::verifyMatch(CheckerContext &C, const SVal &Iter1, // Verify match between the containers of two iterators auto State = C.getState(); const auto *Pos1 = getIteratorPosition(State, Iter1); + if (!Pos1) + return; + + const auto *IterCont1 = Pos1->getContainer(); + + // Skip symbolic regions based on conjured symbols. Two conjured symbols + // may or may not be the same. For example, the same function can return + // the same or a different container but we get different conjured symbols + // for each call. This may cause false positives so omit them from the check. + if (const auto *ContSym = IterCont1->getSymbolicBase()) { + if (isa<SymbolConjured>(ContSym->getSymbol())) + return; + } + const auto *Pos2 = getIteratorPosition(State, Iter2); - if (Pos1 && Pos2 && Pos1->getContainer() != Pos2->getContainer()) { + if (!Pos2) + return; + + const auto *IterCont2 = Pos2->getContainer(); + if (const auto *ContSym = IterCont2->getSymbolicBase()) { + if (isa<SymbolConjured>(ContSym->getSymbol())) + return; + } + + if (IterCont1 != IterCont2) { auto *N = C.generateNonFatalErrorNode(State); if (!N) return; diff --git a/clang/test/Analysis/mismatched-iterator.cpp b/clang/test/Analysis/mismatched-iterator.cpp index 756d0954435..26a71c399c7 100644 --- a/clang/test/Analysis/mismatched-iterator.cpp +++ b/clang/test/Analysis/mismatched-iterator.cpp @@ -189,3 +189,17 @@ void bad_comparison(std::vector<int> &v1, std::vector<int> &v2) { *v1.cbegin(); } } + +std::vector<int> &return_vector_ref(); + +void ignore_conjured1() { + std::vector<int> &v1 = return_vector_ref(), &v2 = return_vector_ref(); + + v2.erase(v1.cbegin()); // no-warning +} + +void ignore_conjured2() { + std::vector<int> &v1 = return_vector_ref(), &v2 = return_vector_ref(); + + if (v1.cbegin() == v2.cbegin()) {} //no-warning +} |

