xref: /freebsd-src/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/Iterator.cpp (revision 5ffd83dbcc34f10e07f6d3e968ae6365869615f4)
1480093f4SDimitry Andric //=== Iterator.cpp - Common functions for iterator checkers. -------*- C++ -*-//
2480093f4SDimitry Andric //
3480093f4SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4480093f4SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5480093f4SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6480093f4SDimitry Andric //
7480093f4SDimitry Andric //===----------------------------------------------------------------------===//
8480093f4SDimitry Andric //
9480093f4SDimitry Andric // Defines common functions to be used by the itertor checkers .
10480093f4SDimitry Andric //
11480093f4SDimitry Andric //===----------------------------------------------------------------------===//
12480093f4SDimitry Andric 
13480093f4SDimitry Andric #include "Iterator.h"
14480093f4SDimitry Andric 
15480093f4SDimitry Andric namespace clang {
16480093f4SDimitry Andric namespace ento {
17480093f4SDimitry Andric namespace iterator {
18480093f4SDimitry Andric 
19480093f4SDimitry Andric bool isIteratorType(const QualType &Type) {
20480093f4SDimitry Andric   if (Type->isPointerType())
21480093f4SDimitry Andric     return true;
22480093f4SDimitry Andric 
23480093f4SDimitry Andric   const auto *CRD = Type->getUnqualifiedDesugaredType()->getAsCXXRecordDecl();
24480093f4SDimitry Andric   return isIterator(CRD);
25480093f4SDimitry Andric }
26480093f4SDimitry Andric 
27480093f4SDimitry Andric bool isIterator(const CXXRecordDecl *CRD) {
28480093f4SDimitry Andric   if (!CRD)
29480093f4SDimitry Andric     return false;
30480093f4SDimitry Andric 
31480093f4SDimitry Andric   const auto Name = CRD->getName();
32480093f4SDimitry Andric   if (!(Name.endswith_lower("iterator") || Name.endswith_lower("iter") ||
33480093f4SDimitry Andric         Name.endswith_lower("it")))
34480093f4SDimitry Andric     return false;
35480093f4SDimitry Andric 
36480093f4SDimitry Andric   bool HasCopyCtor = false, HasCopyAssign = true, HasDtor = false,
37480093f4SDimitry Andric        HasPreIncrOp = false, HasPostIncrOp = false, HasDerefOp = false;
38480093f4SDimitry Andric   for (const auto *Method : CRD->methods()) {
39480093f4SDimitry Andric     if (const auto *Ctor = dyn_cast<CXXConstructorDecl>(Method)) {
40480093f4SDimitry Andric       if (Ctor->isCopyConstructor()) {
41480093f4SDimitry Andric         HasCopyCtor = !Ctor->isDeleted() && Ctor->getAccess() == AS_public;
42480093f4SDimitry Andric       }
43480093f4SDimitry Andric       continue;
44480093f4SDimitry Andric     }
45480093f4SDimitry Andric     if (const auto *Dtor = dyn_cast<CXXDestructorDecl>(Method)) {
46480093f4SDimitry Andric       HasDtor = !Dtor->isDeleted() && Dtor->getAccess() == AS_public;
47480093f4SDimitry Andric       continue;
48480093f4SDimitry Andric     }
49480093f4SDimitry Andric     if (Method->isCopyAssignmentOperator()) {
50480093f4SDimitry Andric       HasCopyAssign = !Method->isDeleted() && Method->getAccess() == AS_public;
51480093f4SDimitry Andric       continue;
52480093f4SDimitry Andric     }
53480093f4SDimitry Andric     if (!Method->isOverloadedOperator())
54480093f4SDimitry Andric       continue;
55480093f4SDimitry Andric     const auto OPK = Method->getOverloadedOperator();
56480093f4SDimitry Andric     if (OPK == OO_PlusPlus) {
57480093f4SDimitry Andric       HasPreIncrOp = HasPreIncrOp || (Method->getNumParams() == 0);
58480093f4SDimitry Andric       HasPostIncrOp = HasPostIncrOp || (Method->getNumParams() == 1);
59480093f4SDimitry Andric       continue;
60480093f4SDimitry Andric     }
61480093f4SDimitry Andric     if (OPK == OO_Star) {
62480093f4SDimitry Andric       HasDerefOp = (Method->getNumParams() == 0);
63480093f4SDimitry Andric       continue;
64480093f4SDimitry Andric     }
65480093f4SDimitry Andric   }
66480093f4SDimitry Andric 
67480093f4SDimitry Andric   return HasCopyCtor && HasCopyAssign && HasDtor && HasPreIncrOp &&
68480093f4SDimitry Andric          HasPostIncrOp && HasDerefOp;
69480093f4SDimitry Andric }
70480093f4SDimitry Andric 
71480093f4SDimitry Andric bool isComparisonOperator(OverloadedOperatorKind OK) {
72480093f4SDimitry Andric   return OK == OO_EqualEqual || OK == OO_ExclaimEqual || OK == OO_Less ||
73480093f4SDimitry Andric          OK == OO_LessEqual || OK == OO_Greater || OK == OO_GreaterEqual;
74480093f4SDimitry Andric }
75480093f4SDimitry Andric 
76480093f4SDimitry Andric bool isInsertCall(const FunctionDecl *Func) {
77480093f4SDimitry Andric   const auto *IdInfo = Func->getIdentifier();
78480093f4SDimitry Andric   if (!IdInfo)
79480093f4SDimitry Andric     return false;
80480093f4SDimitry Andric   if (Func->getNumParams() < 2 || Func->getNumParams() > 3)
81480093f4SDimitry Andric     return false;
82480093f4SDimitry Andric   if (!isIteratorType(Func->getParamDecl(0)->getType()))
83480093f4SDimitry Andric     return false;
84480093f4SDimitry Andric   return IdInfo->getName() == "insert";
85480093f4SDimitry Andric }
86480093f4SDimitry Andric 
87480093f4SDimitry Andric bool isEmplaceCall(const FunctionDecl *Func) {
88480093f4SDimitry Andric   const auto *IdInfo = Func->getIdentifier();
89480093f4SDimitry Andric   if (!IdInfo)
90480093f4SDimitry Andric     return false;
91480093f4SDimitry Andric   if (Func->getNumParams() < 2)
92480093f4SDimitry Andric     return false;
93480093f4SDimitry Andric   if (!isIteratorType(Func->getParamDecl(0)->getType()))
94480093f4SDimitry Andric     return false;
95480093f4SDimitry Andric   return IdInfo->getName() == "emplace";
96480093f4SDimitry Andric }
97480093f4SDimitry Andric 
98480093f4SDimitry Andric bool isEraseCall(const FunctionDecl *Func) {
99480093f4SDimitry Andric   const auto *IdInfo = Func->getIdentifier();
100480093f4SDimitry Andric   if (!IdInfo)
101480093f4SDimitry Andric     return false;
102480093f4SDimitry Andric   if (Func->getNumParams() < 1 || Func->getNumParams() > 2)
103480093f4SDimitry Andric     return false;
104480093f4SDimitry Andric   if (!isIteratorType(Func->getParamDecl(0)->getType()))
105480093f4SDimitry Andric     return false;
106480093f4SDimitry Andric   if (Func->getNumParams() == 2 &&
107480093f4SDimitry Andric       !isIteratorType(Func->getParamDecl(1)->getType()))
108480093f4SDimitry Andric     return false;
109480093f4SDimitry Andric   return IdInfo->getName() == "erase";
110480093f4SDimitry Andric }
111480093f4SDimitry Andric 
112480093f4SDimitry Andric bool isEraseAfterCall(const FunctionDecl *Func) {
113480093f4SDimitry Andric   const auto *IdInfo = Func->getIdentifier();
114480093f4SDimitry Andric   if (!IdInfo)
115480093f4SDimitry Andric     return false;
116480093f4SDimitry Andric   if (Func->getNumParams() < 1 || Func->getNumParams() > 2)
117480093f4SDimitry Andric     return false;
118480093f4SDimitry Andric   if (!isIteratorType(Func->getParamDecl(0)->getType()))
119480093f4SDimitry Andric     return false;
120480093f4SDimitry Andric   if (Func->getNumParams() == 2 &&
121480093f4SDimitry Andric       !isIteratorType(Func->getParamDecl(1)->getType()))
122480093f4SDimitry Andric     return false;
123480093f4SDimitry Andric   return IdInfo->getName() == "erase_after";
124480093f4SDimitry Andric }
125480093f4SDimitry Andric 
126480093f4SDimitry Andric bool isAccessOperator(OverloadedOperatorKind OK) {
127480093f4SDimitry Andric   return isDereferenceOperator(OK) || isIncrementOperator(OK) ||
128480093f4SDimitry Andric          isDecrementOperator(OK) || isRandomIncrOrDecrOperator(OK);
129480093f4SDimitry Andric }
130480093f4SDimitry Andric 
131*5ffd83dbSDimitry Andric bool isAccessOperator(UnaryOperatorKind OK) {
132*5ffd83dbSDimitry Andric   return isDereferenceOperator(OK) || isIncrementOperator(OK) ||
133*5ffd83dbSDimitry Andric          isDecrementOperator(OK);
134*5ffd83dbSDimitry Andric }
135*5ffd83dbSDimitry Andric 
136*5ffd83dbSDimitry Andric bool isAccessOperator(BinaryOperatorKind OK) {
137*5ffd83dbSDimitry Andric   return isDereferenceOperator(OK) || isRandomIncrOrDecrOperator(OK);
138*5ffd83dbSDimitry Andric }
139*5ffd83dbSDimitry Andric 
140480093f4SDimitry Andric bool isDereferenceOperator(OverloadedOperatorKind OK) {
141480093f4SDimitry Andric   return OK == OO_Star || OK == OO_Arrow || OK == OO_ArrowStar ||
142480093f4SDimitry Andric          OK == OO_Subscript;
143480093f4SDimitry Andric }
144480093f4SDimitry Andric 
145*5ffd83dbSDimitry Andric bool isDereferenceOperator(UnaryOperatorKind OK) {
146*5ffd83dbSDimitry Andric   return OK == UO_Deref;
147*5ffd83dbSDimitry Andric }
148*5ffd83dbSDimitry Andric 
149*5ffd83dbSDimitry Andric bool isDereferenceOperator(BinaryOperatorKind OK) {
150*5ffd83dbSDimitry Andric   return OK == BO_PtrMemI;
151*5ffd83dbSDimitry Andric }
152*5ffd83dbSDimitry Andric 
153480093f4SDimitry Andric bool isIncrementOperator(OverloadedOperatorKind OK) {
154480093f4SDimitry Andric   return OK == OO_PlusPlus;
155480093f4SDimitry Andric }
156480093f4SDimitry Andric 
157*5ffd83dbSDimitry Andric bool isIncrementOperator(UnaryOperatorKind OK) {
158*5ffd83dbSDimitry Andric   return OK == UO_PreInc || OK == UO_PostInc;
159*5ffd83dbSDimitry Andric }
160*5ffd83dbSDimitry Andric 
161480093f4SDimitry Andric bool isDecrementOperator(OverloadedOperatorKind OK) {
162480093f4SDimitry Andric   return OK == OO_MinusMinus;
163480093f4SDimitry Andric }
164480093f4SDimitry Andric 
165*5ffd83dbSDimitry Andric bool isDecrementOperator(UnaryOperatorKind OK) {
166*5ffd83dbSDimitry Andric   return OK == UO_PreDec || OK == UO_PostDec;
167*5ffd83dbSDimitry Andric }
168*5ffd83dbSDimitry Andric 
169480093f4SDimitry Andric bool isRandomIncrOrDecrOperator(OverloadedOperatorKind OK) {
170480093f4SDimitry Andric   return OK == OO_Plus || OK == OO_PlusEqual || OK == OO_Minus ||
171480093f4SDimitry Andric          OK == OO_MinusEqual;
172480093f4SDimitry Andric }
173480093f4SDimitry Andric 
174*5ffd83dbSDimitry Andric bool isRandomIncrOrDecrOperator(BinaryOperatorKind OK) {
175*5ffd83dbSDimitry Andric   return OK == BO_Add || OK == BO_AddAssign ||
176*5ffd83dbSDimitry Andric          OK == BO_Sub || OK == BO_SubAssign;
177*5ffd83dbSDimitry Andric }
178*5ffd83dbSDimitry Andric 
179480093f4SDimitry Andric const ContainerData *getContainerData(ProgramStateRef State,
180480093f4SDimitry Andric                                       const MemRegion *Cont) {
181480093f4SDimitry Andric   return State->get<ContainerMap>(Cont);
182480093f4SDimitry Andric }
183480093f4SDimitry Andric 
184480093f4SDimitry Andric const IteratorPosition *getIteratorPosition(ProgramStateRef State,
185480093f4SDimitry Andric                                             const SVal &Val) {
186480093f4SDimitry Andric   if (auto Reg = Val.getAsRegion()) {
187480093f4SDimitry Andric     Reg = Reg->getMostDerivedObjectRegion();
188480093f4SDimitry Andric     return State->get<IteratorRegionMap>(Reg);
189480093f4SDimitry Andric   } else if (const auto Sym = Val.getAsSymbol()) {
190480093f4SDimitry Andric     return State->get<IteratorSymbolMap>(Sym);
191480093f4SDimitry Andric   } else if (const auto LCVal = Val.getAs<nonloc::LazyCompoundVal>()) {
192480093f4SDimitry Andric     return State->get<IteratorRegionMap>(LCVal->getRegion());
193480093f4SDimitry Andric   }
194480093f4SDimitry Andric   return nullptr;
195480093f4SDimitry Andric }
196480093f4SDimitry Andric 
197480093f4SDimitry Andric ProgramStateRef setIteratorPosition(ProgramStateRef State, const SVal &Val,
198480093f4SDimitry Andric                                     const IteratorPosition &Pos) {
199480093f4SDimitry Andric   if (auto Reg = Val.getAsRegion()) {
200480093f4SDimitry Andric     Reg = Reg->getMostDerivedObjectRegion();
201480093f4SDimitry Andric     return State->set<IteratorRegionMap>(Reg, Pos);
202480093f4SDimitry Andric   } else if (const auto Sym = Val.getAsSymbol()) {
203480093f4SDimitry Andric     return State->set<IteratorSymbolMap>(Sym, Pos);
204480093f4SDimitry Andric   } else if (const auto LCVal = Val.getAs<nonloc::LazyCompoundVal>()) {
205480093f4SDimitry Andric     return State->set<IteratorRegionMap>(LCVal->getRegion(), Pos);
206480093f4SDimitry Andric   }
207480093f4SDimitry Andric   return nullptr;
208480093f4SDimitry Andric }
209480093f4SDimitry Andric 
210*5ffd83dbSDimitry Andric ProgramStateRef createIteratorPosition(ProgramStateRef State, const SVal &Val,
211*5ffd83dbSDimitry Andric                                        const MemRegion *Cont, const Stmt* S,
212*5ffd83dbSDimitry Andric                                        const LocationContext *LCtx,
213*5ffd83dbSDimitry Andric                                        unsigned blockCount) {
214*5ffd83dbSDimitry Andric   auto &StateMgr = State->getStateManager();
215*5ffd83dbSDimitry Andric   auto &SymMgr = StateMgr.getSymbolManager();
216*5ffd83dbSDimitry Andric   auto &ACtx = StateMgr.getContext();
217*5ffd83dbSDimitry Andric 
218*5ffd83dbSDimitry Andric   auto Sym = SymMgr.conjureSymbol(S, LCtx, ACtx.LongTy, blockCount);
219*5ffd83dbSDimitry Andric   State = assumeNoOverflow(State, Sym, 4);
220*5ffd83dbSDimitry Andric   return setIteratorPosition(State, Val,
221*5ffd83dbSDimitry Andric                              IteratorPosition::getPosition(Cont, Sym));
222*5ffd83dbSDimitry Andric }
223*5ffd83dbSDimitry Andric 
224480093f4SDimitry Andric ProgramStateRef advancePosition(ProgramStateRef State, const SVal &Iter,
225480093f4SDimitry Andric                                 OverloadedOperatorKind Op,
226480093f4SDimitry Andric                                 const SVal &Distance) {
227480093f4SDimitry Andric   const auto *Pos = getIteratorPosition(State, Iter);
228480093f4SDimitry Andric   if (!Pos)
229480093f4SDimitry Andric     return nullptr;
230480093f4SDimitry Andric 
231480093f4SDimitry Andric   auto &SymMgr = State->getStateManager().getSymbolManager();
232480093f4SDimitry Andric   auto &SVB = State->getStateManager().getSValBuilder();
233*5ffd83dbSDimitry Andric   auto &BVF = State->getStateManager().getBasicVals();
234480093f4SDimitry Andric 
235480093f4SDimitry Andric   assert ((Op == OO_Plus || Op == OO_PlusEqual ||
236480093f4SDimitry Andric            Op == OO_Minus || Op == OO_MinusEqual) &&
237480093f4SDimitry Andric           "Advance operator must be one of +, -, += and -=.");
238480093f4SDimitry Andric   auto BinOp = (Op == OO_Plus || Op == OO_PlusEqual) ? BO_Add : BO_Sub;
239*5ffd83dbSDimitry Andric   const auto IntDistOp = Distance.getAs<nonloc::ConcreteInt>();
240*5ffd83dbSDimitry Andric   if (!IntDistOp)
241*5ffd83dbSDimitry Andric     return nullptr;
242*5ffd83dbSDimitry Andric 
243480093f4SDimitry Andric   // For concrete integers we can calculate the new position
244*5ffd83dbSDimitry Andric   nonloc::ConcreteInt IntDist = *IntDistOp;
245*5ffd83dbSDimitry Andric 
246*5ffd83dbSDimitry Andric   if (IntDist.getValue().isNegative()) {
247*5ffd83dbSDimitry Andric     IntDist = nonloc::ConcreteInt(BVF.getValue(-IntDist.getValue()));
248*5ffd83dbSDimitry Andric     BinOp = (BinOp == BO_Add) ? BO_Sub : BO_Add;
249*5ffd83dbSDimitry Andric   }
250480093f4SDimitry Andric   const auto NewPos =
251480093f4SDimitry Andric     Pos->setTo(SVB.evalBinOp(State, BinOp,
252480093f4SDimitry Andric                              nonloc::SymbolVal(Pos->getOffset()),
253*5ffd83dbSDimitry Andric                              IntDist, SymMgr.getType(Pos->getOffset()))
254480093f4SDimitry Andric                .getAsSymbol());
255480093f4SDimitry Andric   return setIteratorPosition(State, Iter, NewPos);
256480093f4SDimitry Andric }
257480093f4SDimitry Andric 
258*5ffd83dbSDimitry Andric // This function tells the analyzer's engine that symbols produced by our
259*5ffd83dbSDimitry Andric // checker, most notably iterator positions, are relatively small.
260*5ffd83dbSDimitry Andric // A distance between items in the container should not be very large.
261*5ffd83dbSDimitry Andric // By assuming that it is within around 1/8 of the address space,
262*5ffd83dbSDimitry Andric // we can help the analyzer perform operations on these symbols
263*5ffd83dbSDimitry Andric // without being afraid of integer overflows.
264*5ffd83dbSDimitry Andric // FIXME: Should we provide it as an API, so that all checkers could use it?
265*5ffd83dbSDimitry Andric ProgramStateRef assumeNoOverflow(ProgramStateRef State, SymbolRef Sym,
266*5ffd83dbSDimitry Andric                                  long Scale) {
267*5ffd83dbSDimitry Andric   SValBuilder &SVB = State->getStateManager().getSValBuilder();
268*5ffd83dbSDimitry Andric   BasicValueFactory &BV = SVB.getBasicValueFactory();
269*5ffd83dbSDimitry Andric 
270*5ffd83dbSDimitry Andric   QualType T = Sym->getType();
271*5ffd83dbSDimitry Andric   assert(T->isSignedIntegerOrEnumerationType());
272*5ffd83dbSDimitry Andric   APSIntType AT = BV.getAPSIntType(T);
273*5ffd83dbSDimitry Andric 
274*5ffd83dbSDimitry Andric   ProgramStateRef NewState = State;
275*5ffd83dbSDimitry Andric 
276*5ffd83dbSDimitry Andric   llvm::APSInt Max = AT.getMaxValue() / AT.getValue(Scale);
277*5ffd83dbSDimitry Andric   SVal IsCappedFromAbove =
278*5ffd83dbSDimitry Andric       SVB.evalBinOpNN(State, BO_LE, nonloc::SymbolVal(Sym),
279*5ffd83dbSDimitry Andric                       nonloc::ConcreteInt(Max), SVB.getConditionType());
280*5ffd83dbSDimitry Andric   if (auto DV = IsCappedFromAbove.getAs<DefinedSVal>()) {
281*5ffd83dbSDimitry Andric     NewState = NewState->assume(*DV, true);
282*5ffd83dbSDimitry Andric     if (!NewState)
283*5ffd83dbSDimitry Andric       return State;
284*5ffd83dbSDimitry Andric   }
285*5ffd83dbSDimitry Andric 
286*5ffd83dbSDimitry Andric   llvm::APSInt Min = -Max;
287*5ffd83dbSDimitry Andric   SVal IsCappedFromBelow =
288*5ffd83dbSDimitry Andric       SVB.evalBinOpNN(State, BO_GE, nonloc::SymbolVal(Sym),
289*5ffd83dbSDimitry Andric                       nonloc::ConcreteInt(Min), SVB.getConditionType());
290*5ffd83dbSDimitry Andric   if (auto DV = IsCappedFromBelow.getAs<DefinedSVal>()) {
291*5ffd83dbSDimitry Andric     NewState = NewState->assume(*DV, true);
292*5ffd83dbSDimitry Andric     if (!NewState)
293*5ffd83dbSDimitry Andric       return State;
294*5ffd83dbSDimitry Andric   }
295*5ffd83dbSDimitry Andric 
296*5ffd83dbSDimitry Andric   return NewState;
297480093f4SDimitry Andric }
298480093f4SDimitry Andric 
299480093f4SDimitry Andric bool compare(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2,
300480093f4SDimitry Andric              BinaryOperator::Opcode Opc) {
301480093f4SDimitry Andric   return compare(State, nonloc::SymbolVal(Sym1), nonloc::SymbolVal(Sym2), Opc);
302480093f4SDimitry Andric }
303480093f4SDimitry Andric 
304480093f4SDimitry Andric bool compare(ProgramStateRef State, NonLoc NL1, NonLoc NL2,
305480093f4SDimitry Andric              BinaryOperator::Opcode Opc) {
306480093f4SDimitry Andric   auto &SVB = State->getStateManager().getSValBuilder();
307480093f4SDimitry Andric 
308480093f4SDimitry Andric   const auto comparison =
309480093f4SDimitry Andric     SVB.evalBinOp(State, Opc, NL1, NL2, SVB.getConditionType());
310480093f4SDimitry Andric 
311480093f4SDimitry Andric   assert(comparison.getAs<DefinedSVal>() &&
312480093f4SDimitry Andric     "Symbol comparison must be a `DefinedSVal`");
313480093f4SDimitry Andric 
314480093f4SDimitry Andric   return !State->assume(comparison.castAs<DefinedSVal>(), false);
315480093f4SDimitry Andric }
316480093f4SDimitry Andric 
317480093f4SDimitry Andric } // namespace iterator
318480093f4SDimitry Andric } // namespace ento
319480093f4SDimitry Andric } // namespace clang
320