//=== Iterator.h - Common functions for iterator checkers. ---------*- C++ -*-// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // Defines common functions to be used by the itertor checkers . // //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_ITERATOR_H #define LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_ITERATOR_H #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicType.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" #include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h" namespace clang { namespace ento { namespace iterator { // Abstract position of an iterator. This helps to handle all three kinds // of operators in a common way by using a symbolic position. struct IteratorPosition { private: // Container the iterator belongs to const MemRegion *Cont; // Whether iterator is valid const bool Valid; // Abstract offset const SymbolRef Offset; IteratorPosition(const MemRegion *C, bool V, SymbolRef Of) : Cont(C), Valid(V), Offset(Of) {} public: const MemRegion *getContainer() const { return Cont; } bool isValid() const { return Valid; } SymbolRef getOffset() const { return Offset; } IteratorPosition invalidate() const { return IteratorPosition(Cont, false, Offset); } static IteratorPosition getPosition(const MemRegion *C, SymbolRef Of) { return IteratorPosition(C, true, Of); } IteratorPosition setTo(SymbolRef NewOf) const { return IteratorPosition(Cont, Valid, NewOf); } IteratorPosition reAssign(const MemRegion *NewCont) const { return IteratorPosition(NewCont, Valid, Offset); } bool operator==(const IteratorPosition &X) const { return Cont == X.Cont && Valid == X.Valid && Offset == X.Offset; } bool operator!=(const IteratorPosition &X) const { return !(*this == X); } void Profile(llvm::FoldingSetNodeID &ID) const { ID.AddPointer(Cont); ID.AddInteger(Valid); ID.Add(Offset); } }; // Structure to record the symbolic begin and end position of a container struct ContainerData { private: const SymbolRef Begin, End; ContainerData(SymbolRef B, SymbolRef E) : Begin(B), End(E) {} public: static ContainerData fromBegin(SymbolRef B) { return ContainerData(B, nullptr); } static ContainerData fromEnd(SymbolRef E) { return ContainerData(nullptr, E); } SymbolRef getBegin() const { return Begin; } SymbolRef getEnd() const { return End; } ContainerData newBegin(SymbolRef B) const { return ContainerData(B, End); } ContainerData newEnd(SymbolRef E) const { return ContainerData(Begin, E); } bool operator==(const ContainerData &X) const { return Begin == X.Begin && End == X.End; } bool operator!=(const ContainerData &X) const { return !(*this == X); } void Profile(llvm::FoldingSetNodeID &ID) const { ID.Add(Begin); ID.Add(End); } }; class IteratorSymbolMap {}; class IteratorRegionMap {}; class ContainerMap {}; using IteratorSymbolMapTy = CLANG_ENTO_PROGRAMSTATE_MAP(SymbolRef, IteratorPosition); using IteratorRegionMapTy = CLANG_ENTO_PROGRAMSTATE_MAP(const MemRegion *, IteratorPosition); using ContainerMapTy = CLANG_ENTO_PROGRAMSTATE_MAP(const MemRegion *, ContainerData); } // namespace iterator template<> struct ProgramStateTrait : public ProgramStatePartialTrait { static void *GDMIndex() { static int Index; return &Index; } }; template<> struct ProgramStateTrait : public ProgramStatePartialTrait { static void *GDMIndex() { static int Index; return &Index; } }; template<> struct ProgramStateTrait : public ProgramStatePartialTrait { static void *GDMIndex() { static int Index; return &Index; } }; namespace iterator { bool isIteratorType(const QualType &Type); bool isIterator(const CXXRecordDecl *CRD); bool isComparisonOperator(OverloadedOperatorKind OK); bool isInsertCall(const FunctionDecl *Func); bool isEraseCall(const FunctionDecl *Func); bool isEraseAfterCall(const FunctionDecl *Func); bool isEmplaceCall(const FunctionDecl *Func); bool isAccessOperator(OverloadedOperatorKind OK); bool isAccessOperator(UnaryOperatorKind OK); bool isAccessOperator(BinaryOperatorKind OK); bool isDereferenceOperator(OverloadedOperatorKind OK); bool isDereferenceOperator(UnaryOperatorKind OK); bool isDereferenceOperator(BinaryOperatorKind OK); bool isIncrementOperator(OverloadedOperatorKind OK); bool isIncrementOperator(UnaryOperatorKind OK); bool isDecrementOperator(OverloadedOperatorKind OK); bool isDecrementOperator(UnaryOperatorKind OK); bool isRandomIncrOrDecrOperator(OverloadedOperatorKind OK); bool isRandomIncrOrDecrOperator(BinaryOperatorKind OK); const ContainerData *getContainerData(ProgramStateRef State, const MemRegion *Cont); const IteratorPosition *getIteratorPosition(ProgramStateRef State, SVal Val); ProgramStateRef setIteratorPosition(ProgramStateRef State, SVal Val, const IteratorPosition &Pos); ProgramStateRef createIteratorPosition(ProgramStateRef State, SVal Val, const MemRegion *Cont, const Stmt *S, const LocationContext *LCtx, unsigned blockCount); ProgramStateRef advancePosition(ProgramStateRef State, SVal Iter, OverloadedOperatorKind Op, SVal Distance); ProgramStateRef assumeNoOverflow(ProgramStateRef State, SymbolRef Sym, long Scale); bool compare(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2, BinaryOperator::Opcode Opc); bool compare(ProgramStateRef State, NonLoc NL1, NonLoc NL2, BinaryOperator::Opcode Opc); } // namespace iterator } // namespace ento } // namespace clang #endif