192 lines
6.3 KiB
C
192 lines
6.3 KiB
C
|
//=== 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 Cont != X.Cont || Valid != X.Valid || Offset != X.Offset;
|
||
|
}
|
||
|
|
||
|
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 Begin != X.Begin || End != X.End;
|
||
|
}
|
||
|
|
||
|
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<iterator::IteratorSymbolMap>
|
||
|
: public ProgramStatePartialTrait<iterator::IteratorSymbolMapTy> {
|
||
|
static void *GDMIndex() { static int Index; return &Index; }
|
||
|
};
|
||
|
|
||
|
template<>
|
||
|
struct ProgramStateTrait<iterator::IteratorRegionMap>
|
||
|
: public ProgramStatePartialTrait<iterator::IteratorRegionMapTy> {
|
||
|
static void *GDMIndex() { static int Index; return &Index; }
|
||
|
};
|
||
|
|
||
|
template<>
|
||
|
struct ProgramStateTrait<iterator::ContainerMap>
|
||
|
: public ProgramStatePartialTrait<iterator::ContainerMapTy> {
|
||
|
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,
|
||
|
const SVal &Val);
|
||
|
ProgramStateRef setIteratorPosition(ProgramStateRef State, const SVal &Val,
|
||
|
const IteratorPosition &Pos);
|
||
|
ProgramStateRef createIteratorPosition(ProgramStateRef State, const SVal &Val,
|
||
|
const MemRegion *Cont, const Stmt* S,
|
||
|
const LocationContext *LCtx,
|
||
|
unsigned blockCount);
|
||
|
ProgramStateRef advancePosition(ProgramStateRef State,
|
||
|
const SVal &Iter,
|
||
|
OverloadedOperatorKind Op,
|
||
|
const 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
|