@@ -173,11 +173,12 @@ struct ContainerData {
173
173
class IteratorChecker
174
174
: public Checker<check::PreCall, check::PostCall,
175
175
check::PostStmt<MaterializeTemporaryExpr>, check::Bind,
176
- check::LiveSymbols, check::DeadSymbols> {
176
+ check::LiveSymbols, check::DeadSymbols, eval::Call > {
177
177
178
178
std::unique_ptr<BugType> OutOfRangeBugType;
179
179
std::unique_ptr<BugType> MismatchedBugType;
180
180
std::unique_ptr<BugType> InvalidatedBugType;
181
+ std::unique_ptr<BugType> DebugMsgBugType;
181
182
182
183
void handleComparison (CheckerContext &C, const Expr *CE, const SVal &RetVal,
183
184
const SVal &LVal, const SVal &RVal,
@@ -236,14 +237,43 @@ class IteratorChecker
236
237
ExplodedNode *ErrNode) const ;
237
238
void reportInvalidatedBug (const StringRef &Message, const SVal &Val,
238
239
CheckerContext &C, ExplodedNode *ErrNode) const ;
239
-
240
+ template <typename Getter>
241
+ void analyzerContainerDataField (const CallExpr *CE, CheckerContext &C,
242
+ Getter get) const ;
243
+ void analyzerContainerBegin (const CallExpr *CE, CheckerContext &C) const ;
244
+ void analyzerContainerEnd (const CallExpr *CE, CheckerContext &C) const ;
245
+ template <typename Getter>
246
+ void analyzerIteratorDataField (const CallExpr *CE, CheckerContext &C,
247
+ Getter get, SVal Default) const ;
248
+ void analyzerIteratorPosition (const CallExpr *CE, CheckerContext &C) const ;
249
+ void analyzerIteratorContainer (const CallExpr *CE, CheckerContext &C) const ;
250
+ void analyzerIteratorValidity (const CallExpr *CE, CheckerContext &C) const ;
251
+ ExplodedNode *reportDebugMsg (llvm::StringRef Msg, CheckerContext &C) const ;
252
+
253
+ typedef void (IteratorChecker::*FnCheck)(const CallExpr *,
254
+ CheckerContext &) const ;
255
+
256
+ CallDescriptionMap<FnCheck> Callbacks = {
257
+ {{0 , " clang_analyzer_container_begin" , 1 },
258
+ &IteratorChecker::analyzerContainerBegin},
259
+ {{0 , " clang_analyzer_container_end" , 1 },
260
+ &IteratorChecker::analyzerContainerEnd},
261
+ {{0 , " clang_analyzer_iterator_position" , 1 },
262
+ &IteratorChecker::analyzerIteratorPosition},
263
+ {{0 , " clang_analyzer_iterator_container" , 1 },
264
+ &IteratorChecker::analyzerIteratorContainer},
265
+ {{0 , " clang_analyzer_iterator_validity" , 1 },
266
+ &IteratorChecker::analyzerIteratorValidity},
267
+ };
268
+
240
269
public:
241
270
IteratorChecker ();
242
271
243
272
enum CheckKind {
244
273
CK_IteratorRangeChecker,
245
274
CK_MismatchedIteratorChecker,
246
275
CK_InvalidatedIteratorChecker,
276
+ CK_DebugIteratorModeling,
247
277
CK_NumCheckKinds
248
278
};
249
279
@@ -259,6 +289,7 @@ class IteratorChecker
259
289
CheckerContext &C) const ;
260
290
void checkLiveSymbols (ProgramStateRef State, SymbolReaper &SR) const ;
261
291
void checkDeadSymbols (SymbolReaper &SR, CheckerContext &C) const ;
292
+ bool evalCall (const CallEvent &Call, CheckerContext &C) const ;
262
293
};
263
294
} // namespace
264
295
@@ -362,6 +393,9 @@ IteratorChecker::IteratorChecker() {
362
393
/* SuppressOnSink=*/ true ));
363
394
InvalidatedBugType.reset (
364
395
new BugType (this , " Iterator invalidated" , " Misuse of STL APIs" ));
396
+ DebugMsgBugType.reset (
397
+ new BugType (this , " Checking analyzer assumptions" , " debug" ,
398
+ /* SuppressOnSink=*/ true ));
365
399
}
366
400
367
401
void IteratorChecker::checkPreCall (const CallEvent &Call,
@@ -1627,6 +1661,124 @@ void IteratorChecker::reportInvalidatedBug(const StringRef &Message,
1627
1661
C.emitReport (std::move (R));
1628
1662
}
1629
1663
1664
+ bool IteratorChecker::evalCall (const CallEvent &Call,
1665
+ CheckerContext &C) const {
1666
+ if (!ChecksEnabled[CK_DebugIteratorModeling])
1667
+ return false ;
1668
+
1669
+ const auto *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr ());
1670
+ if (!CE)
1671
+ return false ;
1672
+
1673
+ const FnCheck *Handler = Callbacks.lookup (Call);
1674
+ if (!Handler)
1675
+ return false ;
1676
+
1677
+ (this ->**Handler)(CE, C);
1678
+ return true ;
1679
+ }
1680
+
1681
+ template <typename Getter>
1682
+ void IteratorChecker::analyzerContainerDataField (const CallExpr *CE,
1683
+ CheckerContext &C,
1684
+ Getter get) const {
1685
+ if (CE->getNumArgs () == 0 ) {
1686
+ reportDebugMsg (" Missing container argument" , C);
1687
+ return ;
1688
+ }
1689
+
1690
+ auto State = C.getState ();
1691
+ const MemRegion *Cont = C.getSVal (CE->getArg (0 )).getAsRegion ();
1692
+ if (Cont) {
1693
+ const auto *Data = getContainerData (State, Cont);
1694
+ if (Data) {
1695
+ SymbolRef Field = get (Data);
1696
+ if (Field) {
1697
+ State = State->BindExpr (CE, C.getLocationContext (),
1698
+ nonloc::SymbolVal (Field));
1699
+ C.addTransition (State);
1700
+ return ;
1701
+ }
1702
+ }
1703
+ }
1704
+
1705
+ auto &BVF = C.getSValBuilder ().getBasicValueFactory ();
1706
+ State = State->BindExpr (CE, C.getLocationContext (),
1707
+ nonloc::ConcreteInt (BVF.getValue (llvm::APSInt::get (0 ))));
1708
+ }
1709
+
1710
+ void IteratorChecker::analyzerContainerBegin (const CallExpr *CE,
1711
+ CheckerContext &C) const {
1712
+ analyzerContainerDataField (CE, C, [](const ContainerData *D) {
1713
+ return D->getBegin ();
1714
+ });
1715
+ }
1716
+
1717
+ void IteratorChecker::analyzerContainerEnd (const CallExpr *CE,
1718
+ CheckerContext &C) const {
1719
+ analyzerContainerDataField (CE, C, [](const ContainerData *D) {
1720
+ return D->getEnd ();
1721
+ });
1722
+ }
1723
+
1724
+ template <typename Getter>
1725
+ void IteratorChecker::analyzerIteratorDataField (const CallExpr *CE,
1726
+ CheckerContext &C,
1727
+ Getter get,
1728
+ SVal Default) const {
1729
+ if (CE->getNumArgs () == 0 ) {
1730
+ reportDebugMsg (" Missing iterator argument" , C);
1731
+ return ;
1732
+ }
1733
+
1734
+ auto State = C.getState ();
1735
+ SVal V = C.getSVal (CE->getArg (0 ));
1736
+ const auto *Pos = getIteratorPosition (State, V);
1737
+ if (Pos) {
1738
+ State = State->BindExpr (CE, C.getLocationContext (), get (Pos));
1739
+ } else {
1740
+ State = State->BindExpr (CE, C.getLocationContext (), Default);
1741
+ }
1742
+ C.addTransition (State);
1743
+ }
1744
+
1745
+ void IteratorChecker::analyzerIteratorPosition (const CallExpr *CE,
1746
+ CheckerContext &C) const {
1747
+ auto &BVF = C.getSValBuilder ().getBasicValueFactory ();
1748
+ analyzerIteratorDataField (CE, C, [](const IteratorPosition *P) {
1749
+ return nonloc::SymbolVal (P->getOffset ());
1750
+ }, nonloc::ConcreteInt (BVF.getValue (llvm::APSInt::get (0 ))));
1751
+ }
1752
+
1753
+ void IteratorChecker::analyzerIteratorContainer (const CallExpr *CE,
1754
+ CheckerContext &C) const {
1755
+ auto &BVF = C.getSValBuilder ().getBasicValueFactory ();
1756
+ analyzerIteratorDataField (CE, C, [](const IteratorPosition *P) {
1757
+ return loc::MemRegionVal (P->getContainer ());
1758
+ }, loc::ConcreteInt (BVF.getValue (llvm::APSInt::get (0 ))));
1759
+ }
1760
+
1761
+ void IteratorChecker::analyzerIteratorValidity (const CallExpr *CE,
1762
+ CheckerContext &C) const {
1763
+ auto &BVF = C.getSValBuilder ().getBasicValueFactory ();
1764
+ analyzerIteratorDataField (CE, C, [&BVF](const IteratorPosition *P) {
1765
+ return
1766
+ nonloc::ConcreteInt (BVF.getValue (llvm::APSInt::get ((P->isValid ()))));
1767
+ }, nonloc::ConcreteInt (BVF.getValue (llvm::APSInt::get (0 ))));
1768
+ }
1769
+
1770
+ ExplodedNode *IteratorChecker::reportDebugMsg (llvm::StringRef Msg,
1771
+ CheckerContext &C) const {
1772
+ ExplodedNode *N = C.generateNonFatalErrorNode ();
1773
+ if (!N)
1774
+ return nullptr ;
1775
+
1776
+ auto &BR = C.getBugReporter ();
1777
+ BR.emitReport (std::make_unique<PathSensitiveBugReport>(*DebugMsgBugType,
1778
+ Msg, N));
1779
+ return N;
1780
+ }
1781
+
1630
1782
namespace {
1631
1783
1632
1784
bool isLess (ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2);
@@ -2388,3 +2540,4 @@ bool ento::shouldRegisterIteratorModeling(const LangOptions &LO) {
2388
2540
REGISTER_CHECKER (IteratorRangeChecker)
2389
2541
REGISTER_CHECKER(MismatchedIteratorChecker)
2390
2542
REGISTER_CHECKER(InvalidatedIteratorChecker)
2543
+ REGISTER_CHECKER(DebugIteratorModeling)
0 commit comments