29using namespace iterator;
33class ContainerModeling
34 :
public Checker<check::PostCall, check::LiveSymbols, check::DeadSymbols> {
56 const Expr *ContE)
const;
58 const char *Sep)
const override;
61 ContainerModeling() =
default;
75 {{CDM::CXXMethod, {
"clear"}, 0}, &ContainerModeling::handleClear},
76 {{CDM::CXXMethod, {
"assign"}, 2}, &ContainerModeling::handleAssign},
77 {{CDM::CXXMethod, {
"push_back"}, 1}, &ContainerModeling::handlePushBack},
78 {{CDM::CXXMethod, {
"emplace_back"}, 1},
79 &ContainerModeling::handlePushBack},
80 {{CDM::CXXMethod, {
"pop_back"}, 0}, &ContainerModeling::handlePopBack},
81 {{CDM::CXXMethod, {
"push_front"}, 1},
82 &ContainerModeling::handlePushFront},
83 {{CDM::CXXMethod, {
"emplace_front"}, 1},
84 &ContainerModeling::handlePushFront},
85 {{CDM::CXXMethod, {
"pop_front"}, 0}, &ContainerModeling::handlePopFront},
89 {{CDM::CXXMethod, {
"insert"}, 2}, &ContainerModeling::handleInsert},
90 {{CDM::CXXMethod, {
"emplace"}, 2}, &ContainerModeling::handleInsert},
91 {{CDM::CXXMethod, {
"erase"}, 1}, &ContainerModeling::handleErase},
92 {{CDM::CXXMethod, {
"erase_after"}, 1},
93 &ContainerModeling::handleEraseAfter},
97 {{CDM::CXXMethod, {
"erase"}, 2}, &ContainerModeling::handleErase},
98 {{CDM::CXXMethod, {
"erase_after"}, 2},
99 &ContainerModeling::handleEraseAfter},
113 unsigned BlockCount);
117 unsigned BlockCount);
153 const auto *
Func = dyn_cast_or_null<FunctionDecl>(
Call.getDecl());
157 if (
Func->isOverloadedOperator()) {
158 const auto Op =
Func->getOverloadedOperator();
159 if (Op == OO_Equal) {
161 const auto *InstCall = cast<CXXInstanceCall>(&
Call);
162 if (cast<CXXMethodDecl>(
Func)->isMoveAssignmentOperator()) {
172 if (
const auto *InstCall = dyn_cast<CXXInstanceCall>(&
Call)) {
173 const NoItParamFn *Handler0 = NoIterParamFunctions.lookup(
Call);
175 (this->**Handler0)(
C, InstCall->getCXXThisVal(),
176 InstCall->getCXXThisExpr());
180 const OneItParamFn *Handler1 = OneIterParamFunctions.lookup(
Call);
182 (this->**Handler1)(
C, InstCall->getCXXThisVal(),
Call.getArgSVal(0));
186 const TwoItParamFn *Handler2 = TwoIterParamFunctions.lookup(
Call);
188 (this->**Handler2)(
C, InstCall->getCXXThisVal(),
Call.getArgSVal(0),
193 const auto *OrigExpr =
Call.getOriginExpr();
197 if (isBeginCall(
Func)) {
198 handleBegin(
C, OrigExpr,
Call.getReturnValue(),
199 InstCall->getCXXThisVal());
203 if (isEndCall(
Func)) {
204 handleEnd(
C, OrigExpr,
Call.getReturnValue(),
205 InstCall->getCXXThisVal());
216 for (
const auto &Cont : ContMap) {
217 const auto CData = Cont.second;
218 if (CData.getBegin()) {
220 if(
const auto *SIE = dyn_cast<SymIntExpr>(CData.getBegin()))
223 if (CData.getEnd()) {
225 if(
const auto *SIE = dyn_cast<SymIntExpr>(CData.getEnd()))
231void ContainerModeling::checkDeadSymbols(
SymbolReaper &SR,
234 auto State =
C.getState();
237 for (
const auto &Cont : ContMap) {
241 if (!hasLiveIterators(State, Cont.first)) {
247 C.addTransition(State);
260 auto State =
C.getState();
261 auto BeginSym = getContainerBegin(State, ContReg);
263 State = createContainerBegin(State, ContReg, CE,
C.getASTContext().LongTy,
264 C.getLocationContext(),
C.blockCount());
265 BeginSym = getContainerBegin(State, ContReg);
269 C.addTransition(State);
282 auto State =
C.getState();
283 auto EndSym = getContainerEnd(State, ContReg);
285 State = createContainerEnd(State, ContReg, CE,
C.getASTContext().LongTy,
286 C.getLocationContext(),
C.blockCount());
287 EndSym = getContainerEnd(State, ContReg);
291 C.addTransition(State);
295 const Expr *CE,
SVal OldCont)
const {
304 auto State =
C.getState();
307 State = invalidateAllIteratorPositions(State, ContReg);
318 if (
const auto OldEndSym = OldCData->getEnd()) {
323 State = reassignAllIteratorPositionsUnless(State, OldContReg, ContReg,
325 auto &SymMgr =
C.getSymbolManager();
326 auto &SVB =
C.getSValBuilder();
329 SymMgr.conjureSymbol(CE,
C.getLocationContext(),
330 C.getASTContext().LongTy,
C.blockCount());
333 State = setContainerData(State, ContReg, CData->newEnd(NewEndSym));
335 State = setContainerData(State, ContReg,
340 State = rebaseSymbolInIteratorPositionsIf(
341 State, SVB, OldEndSym, NewEndSym, OldEndSym, BO_LT);
345 State = reassignAllIteratorPositions(State, OldContReg, ContReg);
347 if (
const auto OldBeginSym = OldCData->getBegin()) {
352 setContainerData(State, ContReg, CData->newBegin(OldBeginSym));
354 State = setContainerData(State, ContReg,
358 setContainerData(State, OldContReg, OldCData->newBegin(
nullptr));
363 State = reassignAllIteratorPositions(State, OldContReg, ContReg);
367 C.addTransition(State);
371 const Expr *ContE)
const {
379 auto State =
C.getState();
380 State = invalidateAllIteratorPositions(State, ContReg);
381 C.addTransition(State);
385 const Expr *ContE)
const {
394 auto State =
C.getState();
395 if (!hasSubscriptOperator(State, ContReg) ||
396 !backModifiable(State, ContReg)) {
399 if (
const auto EndSym = CData->getEnd()) {
401 invalidateAllIteratorPositionsExcept(State, ContReg, EndSym, BO_GE);
402 C.addTransition(State);
408 getChangeTag(
C,
"became empty", ContReg, ContE);
409 State = invalidateAllIteratorPositions(State, ContReg);
410 C.addTransition(State, ChangeTag);
414 const Expr *ContE)
const {
422 auto State =
C.getState();
423 if (hasSubscriptOperator(State, ContReg) && frontModifiable(State, ContReg)) {
424 State = invalidateAllIteratorPositions(State, ContReg);
425 C.addTransition(State);
434 if (
const auto EndSym = CData->getEnd()) {
435 if (hasSubscriptOperator(State, ContReg)) {
436 State = invalidateIteratorPositions(State, EndSym, BO_GE);
438 auto &SymMgr =
C.getSymbolManager();
439 auto &BVF = SymMgr.getBasicVals();
440 auto &SVB =
C.getSValBuilder();
441 const auto newEndSym =
442 SVB.evalBinOp(State, BO_Add,
445 SymMgr.
getType(EndSym)).getAsSymbol();
447 getChangeTag(
C,
"extended to the back by 1 position", ContReg, ContE);
448 State = setContainerData(State, ContReg, CData->newEnd(newEndSym));
449 C.addTransition(State, ChangeTag);
454 const Expr *ContE)
const {
461 auto State =
C.getState();
466 if (
const auto EndSym = CData->getEnd()) {
467 auto &SymMgr =
C.getSymbolManager();
468 auto &BVF = SymMgr.getBasicVals();
469 auto &SVB =
C.getSValBuilder();
471 SVB.evalBinOp(State, BO_Sub,
474 SymMgr.
getType(EndSym)).getAsSymbol();
476 getChangeTag(
C,
"shrank from the back by 1 position", ContReg, ContE);
480 if (hasSubscriptOperator(State, ContReg) &&
481 backModifiable(State, ContReg)) {
482 State = invalidateIteratorPositions(State, BackSym, BO_GE);
483 State = setContainerData(State, ContReg, CData->newEnd(
nullptr));
485 State = invalidateIteratorPositions(State, BackSym, BO_EQ);
487 auto newEndSym = BackSym;
488 State = setContainerData(State, ContReg, CData->newEnd(newEndSym));
489 C.addTransition(State, ChangeTag);
494 const Expr *ContE)
const {
502 auto State =
C.getState();
503 if (hasSubscriptOperator(State, ContReg)) {
504 State = invalidateAllIteratorPositions(State, ContReg);
505 C.addTransition(State);
511 if (
const auto BeginSym = CData->getBegin()) {
512 auto &SymMgr =
C.getSymbolManager();
513 auto &BVF = SymMgr.getBasicVals();
514 auto &SVB =
C.getSValBuilder();
515 const auto newBeginSym =
516 SVB.evalBinOp(State, BO_Sub,
519 SymMgr.
getType(BeginSym)).getAsSymbol();
521 getChangeTag(
C,
"extended to the front by 1 position", ContReg, ContE);
522 State = setContainerData(State, ContReg, CData->newBegin(newBeginSym));
523 C.addTransition(State, ChangeTag);
529 const Expr *ContE)
const {
536 auto State =
C.getState();
543 if (
const auto BeginSym = CData->getBegin()) {
544 if (hasSubscriptOperator(State, ContReg)) {
545 State = invalidateIteratorPositions(State, BeginSym, BO_LE);
547 State = invalidateIteratorPositions(State, BeginSym, BO_EQ);
549 auto &SymMgr =
C.getSymbolManager();
550 auto &BVF = SymMgr.getBasicVals();
551 auto &SVB =
C.getSValBuilder();
552 const auto newBeginSym =
553 SVB.evalBinOp(State, BO_Add,
556 SymMgr.
getType(BeginSym)).getAsSymbol();
558 getChangeTag(
C,
"shrank from the front by 1 position", ContReg, ContE);
559 State = setContainerData(State, ContReg, CData->newBegin(newBeginSym));
560 C.addTransition(State, ChangeTag);
572 auto State =
C.getState();
579 if (hasSubscriptOperator(State, ContReg) && backModifiable(State, ContReg)) {
580 if (frontModifiable(State, ContReg)) {
581 State = invalidateAllIteratorPositions(State, ContReg);
583 State = invalidateIteratorPositions(State, Pos->getOffset(), BO_GE);
586 if (
const auto EndSym = CData->getEnd()) {
587 State = invalidateIteratorPositions(State, EndSym, BO_GE);
588 State = setContainerData(State, ContReg, CData->newEnd(
nullptr));
591 C.addTransition(State);
603 auto State =
C.getState();
611 if (hasSubscriptOperator(State, ContReg) && backModifiable(State, ContReg)) {
612 if (frontModifiable(State, ContReg)) {
613 State = invalidateAllIteratorPositions(State, ContReg);
615 State = invalidateIteratorPositions(State, Pos->getOffset(), BO_GE);
618 if (
const auto EndSym = CData->getEnd()) {
619 State = invalidateIteratorPositions(State, EndSym, BO_GE);
620 State = setContainerData(State, ContReg, CData->newEnd(
nullptr));
624 State = invalidateIteratorPositions(State, Pos->getOffset(), BO_EQ);
626 C.addTransition(State);
636 auto State =
C.getState();
646 if (hasSubscriptOperator(State, ContReg) && backModifiable(State, ContReg)) {
647 if (frontModifiable(State, ContReg)) {
648 State = invalidateAllIteratorPositions(State, ContReg);
650 State = invalidateIteratorPositions(State, Pos1->getOffset(), BO_GE);
653 if (
const auto EndSym = CData->getEnd()) {
654 State = invalidateIteratorPositions(State, EndSym, BO_GE);
655 State = setContainerData(State, ContReg, CData->newEnd(
nullptr));
659 State = invalidateIteratorPositions(State, Pos1->getOffset(), BO_GE,
660 Pos2->getOffset(), BO_LT);
662 C.addTransition(State);
667 auto State =
C.getState();
674 auto &SymMgr =
C.getSymbolManager();
675 auto &BVF = SymMgr.getBasicVals();
676 auto &SVB =
C.getSValBuilder();
678 SVB.evalBinOp(State, BO_Add,
681 SymMgr.
getType(Pos->getOffset())).getAsSymbol();
682 State = invalidateIteratorPositions(State, NextSym, BO_EQ);
683 C.addTransition(State);
688 auto State =
C.getState();
695 State = invalidateIteratorPositions(State, Pos1->getOffset(), BO_GT,
696 Pos2->getOffset(), BO_LT);
697 C.addTransition(State);
703 const Expr *ContE)
const {
706 if (
const auto *DR = dyn_cast<DeclRegion>(ContReg)) {
707 Name = DR->getDecl()->getName();
709 }
else if (
const auto *DRE =
711 Name = DRE->getDecl()->getName();
720 llvm::raw_svector_ostream Out(Msg);
721 Out <<
"Container " << (!Name.empty() ? (
"'" + Name.str() +
"' ") :
"" )
723 return std::string(Out.str());
727void ContainerModeling::printState(raw_ostream &Out,
ProgramStateRef State,
728 const char *NL,
const char *Sep)
const {
731 if (!ContMap.isEmpty()) {
732 Out << Sep <<
"Container Data :" << NL;
733 for (
const auto &Cont : ContMap) {
736 const auto CData = Cont.second;
737 if (CData.getBegin())
743 CData.getEnd()->dumpToStream(Out);
754 const auto *IdInfo =
Func->getIdentifier();
757 return IdInfo->getName().ends_with_insensitive(
"begin");
761 const auto *IdInfo =
Func->getIdentifier();
764 return IdInfo->getName().ends_with_insensitive(
"end");
773 auto Type = TI.getType();
786 const auto *CRD = getCXXRecordDecl(State, Reg);
790 for (
const auto *Method : CRD->methods()) {
791 if (!Method->isOverloadedOperator())
793 const auto OPK = Method->getOverloadedOperator();
794 if (OPK == OO_Subscript) {
802 const auto *CRD = getCXXRecordDecl(State, Reg);
806 for (
const auto *Method : CRD->methods()) {
807 if (!Method->getDeclName().isIdentifier())
809 if (Method->getName() ==
"push_front" || Method->getName() ==
"pop_front") {
817 const auto *CRD = getCXXRecordDecl(State, Reg);
821 for (
const auto *Method : CRD->methods()) {
822 if (!Method->getDeclName().isIdentifier())
824 if (Method->getName() ==
"push_back" || Method->getName() ==
"pop_back") {
836 return CDataPtr->getBegin();
844 return CDataPtr->getEnd();
850 unsigned BlockCount) {
853 if (CDataPtr && CDataPtr->getBegin())
856 auto &SymMgr = State->getSymbolManager();
862 const auto CData = CDataPtr->newBegin(Sym);
863 return setContainerData(State, Cont, CData);
867 return setContainerData(State, Cont, CData);
873 unsigned BlockCount) {
876 if (CDataPtr && CDataPtr->getEnd())
879 auto &SymMgr = State->getSymbolManager();
885 const auto CData = CDataPtr->newEnd(Sym);
886 return setContainerData(State, Cont, CData);
890 return setContainerData(State, Cont, CData);
898template <
typename Condition,
typename Process>
904 for (
const auto &Reg : RegionMap) {
905 if (Cond(Reg.second)) {
906 RegionMap = RegionMapFactory.add(RegionMap, Reg.first, Proc(Reg.second));
917 for (
const auto &Sym : SymbolMap) {
918 if (Cond(Sym.second)) {
919 SymbolMap = SymbolMapFactory.add(SymbolMap, Sym.first, Proc(Sym.second));
933 return Pos.getContainer() == Cont;
936 return Pos.invalidate();
938 return processIteratorPositions(State, MatchCont, Invalidate);
946 return Pos.getContainer() == Cont &&
947 !
compare(State, Pos.getOffset(), Offset, Opc);
950 return Pos.invalidate();
952 return processIteratorPositions(State, MatchContAndCompare, Invalidate);
959 return compare(State, Pos.getOffset(), Offset, Opc);
962 return Pos.invalidate();
964 return processIteratorPositions(State, Compare, Invalidate);
973 return compare(State, Pos.getOffset(), Offset1, Opc1) &&
974 compare(State, Pos.getOffset(), Offset2, Opc2);
977 return Pos.invalidate();
979 return processIteratorPositions(State, Compare, Invalidate);
986 return Pos.getContainer() == Cont;
989 return Pos.reAssign(NewCont);
991 return processIteratorPositions(State, MatchCont, ReAssign);
1000 return Pos.getContainer() == Cont &&
1001 !
compare(State, Pos.getOffset(), Offset, Opc);
1004 return Pos.reAssign(NewCont);
1006 return processIteratorPositions(State, MatchContAndCompare, ReAssign);
1016 return compare(State, Pos.getOffset(), CondSym, Opc);
1019 return Pos.setTo(rebaseSymbol(State, SVB, Pos.getOffset(), OldSym,
1022 return processIteratorPositions(State, LessThanEnd, RebaseSymbol);
1041 SymMgr.
getType(OrigExpr)).getAsSymbol();
1046 for (
const auto &Reg : RegionMap) {
1047 if (Reg.second.getContainer() == Cont)
1052 for (
const auto &Sym : SymbolMap) {
1053 if (Sym.second.getContainer() == Cont)
1066bool ento::shouldRegisterContainerModeling(
const CheckerManager &mgr) {
1072 diag::err_analyzer_checker_incompatible_analyzer_option)
1073 <<
"aggressive-binary-operation-simplification" <<
"false";
Defines the C++ template declaration subclasses.
static bool handleAssignment(EvalInfo &Info, const Expr *E, const LValue &LVal, QualType LValType, APValue &Val)
Perform an assignment of Val to LVal. Takes ownership of Val.
static bool compare(const PathDiagnostic &X, const PathDiagnostic &Y)
DiagnosticsEngine & getDiagnostics() const
Represents a C++ struct/union/class.
DiagnosticBuilder Report(SourceLocation Loc, unsigned DiagID)
Issue the message to the client.
This represents one expression.
Expr * IgnoreParenCasts() LLVM_READONLY
Skip past any parentheses and casts which might surround this expression until reaching a fixed point...
Represents a function declaration or definition.
It wraps the AnalysisDeclContext to represent both the call stack with the help of StackFrameContext ...
PointerType - C99 6.7.5.1 - Pointer Declarators.
A (possibly-)qualified type.
Base for LValueReferenceType and RValueReferenceType.
The base class of the type hierarchy.
CXXRecordDecl * getAsCXXRecordDecl() const
Retrieves the CXXRecordDecl that this type refers to, either because the type is a RecordType or beca...
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
const T * getAs() const
Member-template getAs<specific type>'.
const Type * getUnqualifiedDesugaredType() const
Return the specified type with any "sugar" removed from the type, removing any typedefs,...
An immutable map from CallDescriptions to arbitrary data.
Represents an abstract call to a function or method along a particular path.
virtual void printState(raw_ostream &Out, ProgramStateRef State, const char *NL, const char *Sep) const
See CheckerManager::runCheckersForPrintState.
const AnalyzerOptions & getAnalyzerOptions() const
CHECKER * registerChecker(AT &&... Args)
Used to register checkers.
ASTContext & getASTContext() const
const LangOptions & getLangOpts() const
MemRegion - The root abstract class for all memory regions.
LLVM_ATTRIBUTE_RETURNS_NONNULL const MemRegion * getMostDerivedObjectRegion() const
Recursively retrieve the region of the most derived class instance of regions of C++ base class insta...
The tag upon which the TagVisitor reacts.
bool isInteresting(SymbolRef sym) const
virtual SVal evalBinOpNN(ProgramStateRef state, BinaryOperator::Opcode op, NonLoc lhs, NonLoc rhs, QualType resultTy)=0
Create a new value which represents a binary expression with two non- location operands.
SymbolManager & getSymbolManager()
SVal - This represents a symbolic expression, which can be either an L-value or an R-value.
void dumpToStream(raw_ostream &OS) const
std::optional< T > getAs() const
Convert to the specified SVal type, returning std::nullopt if this SVal is not of the desired type.
QualType getType(const ASTContext &) const
Try to get a reasonable type for the given value.
const MemRegion * getAsRegion() const
A symbol representing the result of an expression in the case when we do not know anything about what...
A class responsible for cleaning up unused symbols.
void markLive(SymbolRef sym)
Unconditionally marks a symbol as live.
bool isLiveRegion(const MemRegion *region)
Value representing integer constant.
Represents symbolic expression that isn't a location.
const IteratorPosition * getIteratorPosition(ProgramStateRef State, SVal Val)
ProgramStateRef assumeNoOverflow(ProgramStateRef State, SymbolRef Sym, long Scale)
const ContainerData * getContainerData(ProgramStateRef State, const MemRegion *Cont)
ProgramStateRef setIteratorPosition(ProgramStateRef State, SVal Val, const IteratorPosition &Pos)
DynamicTypeInfo getDynamicTypeInfo(ProgramStateRef State, const MemRegion *MR)
Get dynamic type information for the region MR.
ComparisonCategoryResult Compare(const T &X, const T &Y)
Helper to compare two comparable types.
The JSON file list parser is used to communicate input to InstallAPI.
const FunctionProtoType * T
static ContainerData fromEnd(SymbolRef E)
static ContainerData fromBegin(SymbolRef B)
static IteratorPosition getPosition(const MemRegion *C, SymbolRef Of)